﻿using System;
using System.Globalization;
using System.Linq;
using NLite.Data.Dialect;
using NLite.Data.SqlTypes;
using System.Data;
using NLite.Data.Dialect.Function;

namespace NLite.Data
{

    public partial class SqlObject : ProjectionNode, IColumnNode
    {
        protected const string ParameterName = "p";
        protected const byte MaxPrecision = 38;
        protected const byte MaxScale = MaxPrecision;

        public INode Expression { get; set; }
        public SqlObject(NodeType type)
            : base(type)
        {
            Type = SqlType.Empty;
        }
        public SqlObject()
            : base(NodeType.SqlObject)
        {
            Type = SqlType.Empty;
        }

        public bool IsParameter
        {
            get { return NodeType == Data.NodeType.Parameter; }
        }

        public bool IsColumn
        {
            get { return NodeType == Data.NodeType.Column; }
        }

        public bool IsFunction
        {
            get { return NodeType == Data.NodeType.SqlObject; }
        }

        public CriterionNode All(SelectNode subQuery)
        {
            return SubQuery(subQuery, SubQueryType.All);
        }

        public CriterionNode Any(SelectNode subQuery)
        {
            return SubQuery(subQuery, SubQueryType.Any);
        }

        public CriterionNode In(SelectNode subQuery)
        {
            return SubQuery(subQuery, SubQueryType.In);
        }

        public CriterionNode Some(SelectNode subQuery)
        {
            return SubQuery(subQuery, SubQueryType.Some);
        }

        private CriterionNode SubQuery(SelectNode subQuery,SubQueryType type)
        {
            return new SubQuery(Expression ?? this, null, subQuery, type);
        }

        public SqlType Type { get; protected set; }
        public NameIdentity Identity { get; protected set; }
        public string Table { get; protected set; }
        public object Value { get; protected internal set; }

        public T Cast<T>() where T : SqlObject,new()
        {
            var o = new T();
            o.Expression = new FunctionExpression(FunctionView.Cast
                , this.Expression ?? this //source
                , new T() //target
                );
            return o;
        }

        public SqlInt16 ToInt16()
        {
            return Cast<SqlInt16>();
        }
        public SqlInt32 ToInt32()
        {
            return Cast<SqlInt32>();
        }
        public SqlInt64 ToInt64()
        {
            return Cast<SqlInt64>();
        }
        public SqlBoolean ToBoolean()
        {
            return Cast<SqlBoolean>();
        }

        public SqlByte ToByte()
        {
            return Cast<SqlByte>();
        }
        public SqlDouble ToDouble()
        {
            return Cast<SqlDouble>();
        }
        public SqlDecimal ToDecimal()
        {
            return Cast<SqlDecimal>();
        }
        public SqlSingle ToSingle()
        {
            return Cast<SqlSingle>();
        }
        public SqlString ToSqlString()
        {
            return Cast<SqlString>();
        }
        public SqlAnsiString ToAnsiString()
        {
            return Cast<SqlAnsiString>();
        }
        public SqlClob ToClob()
        {
            return Cast<SqlClob>();
        }
        public SqlNClob ToNClob()
        {
            return Cast<SqlNClob>();
        }
        
        public SqlString ToSqlString(int length)
        {
            var o = new SqlString();
            
            o.Expression = new FunctionExpression(FunctionView.Cast
                , this.Expression ?? this //source
                , new SqlString //target
                {
                    Type = SqlType.GetString(length)
                });
            return o;
        }

        public SqlAnsiString ToAnsiString(int length)
        {
            var o = new SqlAnsiString();
            o.Expression = new FunctionExpression(FunctionView.Cast
                , this.Expression ?? this
                , new SqlAnsiString //target
                {
                    Type = SqlType.GetAnsiString(length)
                });
            return o;
        }

        public SqlDecimal ToDecimal(byte bPrec, byte bScale)
        {
            if (bPrec < 1
                || bPrec > MaxPrecision
                //|| bScale < 0
                || bScale > MaxScale
                || bScale > bPrec)
                throw new ArgumentOutOfRangeException("Invalid numeric precision/scale.");


            var o = new SqlDecimal();
            o.Expression = new FunctionExpression(FunctionView.Cast
                , this.Expression ?? this
                , new SqlDecimal //target
                {
                    Type = SqlType.GetSqlType(DbTypeCode.Decimal,bPrec,bScale)
                });
            return o;
        }
    }

    public abstract partial class SqlObject<TExpression, TType> : SqlObject ,IParameterNode
        where TExpression : SqlObject<TExpression, TType>
    {
        public SqlObject(NodeType type) : base(type) { }
        public SqlObject() : base(NodeType.SqlObject) { }

        public override object Clone()
        {
            return this;
        }

        protected virtual TExpression CreateParameter(TType value)
        {
            var ctor = typeof(TExpression).GetConstructor(new Type[] { typeof(string), typeof(TType), typeof(ParameterDirection) });
            return (TExpression)ctor.Invoke(new object[] { ParameterName, value, ParameterDirection.Input });
            
        }
        protected static CriterionNode Compare(TExpression left, CompareOperator op, TExpression right)
        {
            if (left == null)
                throw new ArgumentNullException("left");

            if (object.ReferenceEquals(null, right))
            {
                if (op == CompareOperator.Equal || op == CompareOperator.GreaterThanOrEquals || op == CompareOperator.LessThanOrEquals)
                    return new IsNullNode(left);
                else if (op == CompareOperator.NotEqual)
                    return new NotNode(new IsNullNode(left));
            }

            return new CompareNode(left.Expression ?? left, op, right.Expression ?? right);
        }

        protected static CriterionNode Compare(TExpression left, CompareOperator op, TType right)
        {
            if (left == null)
                throw new ArgumentNullException("left");

            if (object.Equals(null, right))
            {
                if (op == CompareOperator.Equal || op == CompareOperator.GreaterThanOrEquals || op == CompareOperator.LessThanOrEquals)
                    return new IsNullNode(left);
                else if (op == CompareOperator.NotEqual)
                    return new NotNode(new IsNullNode(left));
            }

            return new CompareNode(left.Expression??left, op, left.CreateParameter(right));
        }

        protected static CriterionNode Compare(TType left, CompareOperator op, TExpression right)
        {
            if (right == null)
                throw new ArgumentNullException("right");

            if (object.Equals(null, left))
            {
                if (op == CompareOperator.Equal || op == CompareOperator.GreaterThanOrEquals || op == CompareOperator.LessThanOrEquals)
                    return new IsNullNode(right);
                else if (op == CompareOperator.NotEqual)
                    return new NotNode(new IsNullNode(right));
            }

            return new CompareNode(right.CreateParameter(left), op, right.Expression ?? right);
        }

        protected CriterionNode Compare(CompareOperator op, TExpression value)
        {
            return Compare((TExpression)this, op, value);
        }

        protected CriterionNode Compare(CompareOperator op, TType value)
        {
            return Compare((TExpression)this, op, value);
        }

        #region Equals & NotEquals

        public CriterionNode Equal(TType value)
        {
            return Compare(CompareOperator.Equal, value);
        }

        public CriterionNode Equal(TExpression value)
        {
            return Compare(CompareOperator.Equal, value);
        }

        public CriterionNode NotEqual(TType value)
        {
            return Compare(CompareOperator.NotEqual, value);
        }

        public CriterionNode NotEqual(TExpression value)
        {
            return Compare(CompareOperator.NotEqual, value);
        }
        #endregion



        string IParameterNode.Name
        {
            get { return Identity.Name; }
        }

        
    }

    public sealed partial class SqlBoolean : SqlObject<SqlBoolean, bool?>, ICriterionNode
    {
        public SqlBoolean() : base(NodeType.SqlObject) { Type = SqlType.Boolean; }

        public SqlBoolean(string column, string table)
            : base(NodeType.Column)
        {
            Type = SqlType.Boolean;
            Table = table;
            Identity = NameIdentity.Get(Type, column);
        }
        public SqlBoolean(string parameterName, bool? value, ParameterDirection direction):base(NodeType.Parameter)
        {
            Type = SqlType.Boolean;
            Identity = NameIdentity.Get(Type, parameterName, direction);
            Value = value;
        }

        public new Boolean? Value
        {
            get { return base.Value as Boolean?; }
            internal set { base.Value = value; }
        }
        
        protected override SqlBoolean CreateParameter(bool? value)
        {
            return new SqlBoolean(ParameterName, value, ParameterDirection.Input);
        }

        public CriterionNode And(ICriterionNode exp)
        {
            if (ReferenceEquals(exp, null))
                throw new ArgumentNullException("exp");

            return new AndNode(this, exp);
        }

        public CriterionNode Or(ICriterionNode exp)
        {
            if (ReferenceEquals(exp, null))
                throw new ArgumentNullException("exp");
            return new OrExpression(this, exp);
        }
        public CriterionNode Not()
        {
            return new NotNode(this);
        }

        #region Operators

        #region Equals & NotEquals
        public static CriterionNode operator ==(SqlBoolean left, SqlBoolean right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlBoolean left, SqlBoolean right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(SqlBoolean left, bool? right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlBoolean left, bool? right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(bool? left, SqlBoolean right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(bool? left, SqlBoolean right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }
        #endregion

        public static bool operator true(SqlBoolean right)
        {
            return false;
        }

        public static bool operator false(SqlBoolean right)
        {
            return false;
        }



        public static CriterionNode operator &(SqlBoolean left, SqlBoolean right)
        {
            if (ReferenceEquals(left, null))
                throw new ArgumentNullException("left");

            if (ReferenceEquals(right, null))
                throw new ArgumentNullException("right");

            return new AndNode(left.Clone() as ICriterionNode, right.Clone() as ICriterionNode);
        }



        public static CriterionNode operator |(SqlBoolean left, SqlBoolean right)
        {
            if (ReferenceEquals(left, null))
                throw new ArgumentNullException("left");

            if (ReferenceEquals(right, null))
                throw new ArgumentNullException("right");

            return new OrExpression(left.Clone() as ICriterionNode, right.Clone() as ICriterionNode);
        }

        public static CriterionNode operator &(SqlBoolean left, CriterionNode right)
        {
            if (ReferenceEquals(right, null))
                throw new ArgumentNullException("right");

            if (ReferenceEquals(left, null))
                return right.Clone() as CriterionNode;

            return new AndNode(left.Clone() as ICriterionNode, right.Clone() as ICriterionNode);
        }

        public static CriterionNode operator &(CriterionNode left, SqlBoolean right)
        {
            if (ReferenceEquals(left, null))
                throw new ArgumentNullException("left");

            if (ReferenceEquals(right, null))
                return left.Clone() as CriterionNode;

            return new AndNode(left.Clone() as ICriterionNode, right.Clone() as ICriterionNode);
        }

        public static CriterionNode operator |(SqlBoolean left, CriterionNode right)
        {
            if (ReferenceEquals(right, null))
                throw new ArgumentNullException("right");

            if (ReferenceEquals(left, null))
                return right.Clone() as CriterionNode;

            return new OrExpression(left.Clone() as ICriterionNode, right.Clone() as ICriterionNode);
        }

        public static CriterionNode operator |(CriterionNode left, SqlBoolean right)
        {
            if (ReferenceEquals(left, null))
                throw new ArgumentNullException("left");

            if (ReferenceEquals(right, null))
                return left.Clone() as CriterionNode;

            return new OrExpression(left.Clone() as ICriterionNode, right.Clone() as ICriterionNode);
        }

        public static CriterionNode operator !(SqlBoolean right)
        {
            if (ReferenceEquals(right, null))
                throw new ArgumentNullException("right");

            return new NotNode(right.Clone() as ICriterionNode);
        }

        #endregion

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }
    }

    public abstract class SqlNumber<TExpression, TType> : SqlObject<TExpression, TType> 
        where TExpression : SqlNumber<TExpression, TType>,new()
    {
        public SqlNumber(NodeType type) : base(type) { }
        public SqlNumber() : base(NodeType.SqlObject) { }

        public new TType Value
        {
            get { return (TType)base.Value; }
            protected internal set { base.Value = value; }
        }

        protected static TExpression Arithmetic(TExpression left, ArithmeticOperator op, TExpression right)
        {
            if (object.ReferenceEquals(null, left)) return right;
            if (object.ReferenceEquals(null, right)) return left;

            return left.Arithmetic(op, right);
        }

        protected static TExpression Arithmetic(TType left, ArithmeticOperator op, TExpression right)
        {
            if (object.ReferenceEquals(null, right))
                throw new ArgumentNullException("right");

            return right.CreateParameter(left).Arithmetic(op, right);
        }

        protected static TExpression Arithmetic(TExpression left, ArithmeticOperator op, TType right)
        {
            if (object.ReferenceEquals(null, left))
                throw new ArgumentNullException("left");

            return left.Arithmetic(op, right);
        }

        protected abstract TExpression ArithmeticCore(ArithmeticOperator op, TType value);

        protected TExpression Arithmetic(ArithmeticOperator op, TExpression value)
        {
            if (object.ReferenceEquals(null, value))
                return this as TExpression;

            if (!object.Equals(null, Value) && !object.Equals(null, value.Value))
                return ArithmeticCore(op, value.Value);

            var expr = new TExpression();
            expr.Expression = new ArithmeticNode(this.Expression ?? this, op, value.Expression ?? value);
            return expr;
        }

        protected TExpression Arithmetic(ArithmeticOperator op, TType value)
        {
            if (!object.Equals(null, Value))
                return ArithmeticCore(op,value);

            return Arithmetic(op, CreateParameter(value));
        }

        protected static TExpression InnerMod(TExpression left, TExpression right)
        {
            if (object.ReferenceEquals(null, left)) return right;
            if (object.ReferenceEquals(null, right)) return left;

            return left.Mod(right);
        }

        protected static TExpression InnerMod(TExpression left, TType right)
        {
            if (object.ReferenceEquals(null, left))
                throw new ArgumentNullException("left");

            return left.Mod(right);
        }

        protected static TExpression InnerMod(TType left, TExpression right)
        {
            if (object.ReferenceEquals(null, right))
                throw new ArgumentNullException("right");

            return right.CreateParameter(left).Mod(right);
        }

        protected abstract TExpression ModCore(TType value);

        public TExpression Mod(TType value)
        {
            if (!object.Equals(null, Value))
                return ModCore(value);

            var expr = new TExpression();
            expr.Expression = new FunctionExpression(FunctionView.Math.Mod, this.Expression ?? this, CreateParameter(value));
            return expr;
        }

        public TExpression Mod(TExpression value)
        {
            if (object.ReferenceEquals(null, value))
                return this as TExpression;

            if (!object.Equals(null, Value) && !object.Equals(null, value.Value))
                return ModCore(value.Value);

            var expr = new TExpression();
            expr.Expression = new FunctionExpression(FunctionView.Math.Mod, this.Expression ?? this, value.Expression ?? value);
            return expr;
        }

        public TExpression Abs()
        {
            return new TExpression { Expression = new FunctionExpression(FunctionView.Math.Abs, this) };
        }

        public TExpression Sign()
        {
            return new TExpression { Expression = new FunctionExpression(FunctionView.Math.Sign, this) };
        }

        #region GreaterThan & LessThan
        public CriterionNode GreaterThan(TType value)
        {
            return Compare(CompareOperator.GreaterThan, value);
        }

        public CriterionNode GreaterThan(TExpression value)
        {
            return Compare(CompareOperator.GreaterThan, value);
        }

        public CriterionNode LessThan(TType value)
        {
            return Compare(CompareOperator.LessThan, value);
        }

        public CriterionNode LessThan(TExpression value)
        {
            return Compare(CompareOperator.LessThan, value);
        }
        #endregion

        #region GreaterThanOrEquals & LessThanOrEquals

        public CriterionNode GreaterThanOrEquals(TType value)
        {
            return Compare(CompareOperator.GreaterThanOrEquals, value);
        }

        public CriterionNode GreaterThanOrEquals(TExpression value)
        {
            return Compare(CompareOperator.GreaterThanOrEquals, value);
        }

        public CriterionNode LessThanOrEquals(TType value)
        {
            return Compare(CompareOperator.LessThanOrEquals, value);
        }

        public CriterionNode LessThanOrEquals(TExpression value)
        {
            return Compare(CompareOperator.LessThanOrEquals, value);
        }
        #endregion

        #region + - * / %

        public TExpression Add(TType value)
        {
            return Arithmetic(ArithmeticOperator.Add, value);
        }

        public TExpression Add(TExpression value)
        {
            return Arithmetic(ArithmeticOperator.Add, value);
        }

        public TExpression Subtract(TType value)
        {
            return Arithmetic(ArithmeticOperator.Subtract, value);
        }

        public TExpression Subtract(TExpression value)
        {
            return Arithmetic(ArithmeticOperator.Subtract, value);
        }

        public TExpression Multiply(TType value)
        {
            return Arithmetic(ArithmeticOperator.Multiply, value);
        }

        public TExpression Multiply(TExpression value)
        {
            return Arithmetic(ArithmeticOperator.Multiply, value);
        }

        public TExpression Divide(TType value)
        {
            return Arithmetic(ArithmeticOperator.Divide, value);
        }

        public TExpression Divide(TExpression value)
        {
            return Arithmetic(ArithmeticOperator.Divide, value);
        }

       
        #endregion

        #region Aggregation

        TExpression Aggregation(AggregationOperator op)
        {
            return new TExpression { Expression = new AggregationNode(this, this.Expression, op) };
        }

        public TExpression Avg()
        {
            return Aggregation(AggregationOperator.Avg);
        }

        public TExpression Max()
        {
            return Aggregation(AggregationOperator.Max);
        }

        public TExpression Min()
        {
            return Aggregation(AggregationOperator.Min);
        }

        public TExpression Sum()
        {
            return Aggregation(AggregationOperator.Sum);
        }

        #endregion

        public CriterionNode Between(TType left, TType right)
        {
            return new BetweenNode(this.Expression?? this, CreateParameter(left), CreateParameter(right));
        }

        public CriterionNode In(params TType[] range)
        {
            return SubQuery(range, SubQueryType.In);
        }

        public CriterionNode All(params TType[] range)
        {
            return SubQuery(range, SubQueryType.All);
        }

        public CriterionNode Any(params TType[] range)
        {
            return SubQuery(range, SubQueryType.Any);
        }

        public CriterionNode Some(params TType[] range)
        {
            return SubQuery(range, SubQueryType.Some);
        }

        private CriterionNode SubQuery(TType[] range,SubQueryType type)
        {
            return new SubQuery(this.Expression ?? this, range.Select(p => CreateParameter(p)).Cast<Node>(), null, type);
        }
    }

    public sealed partial class SqlByte : SqlNumber<SqlByte, byte?>
    {
        public SqlByte() : base(NodeType.SqlObject) { Type = SqlType.Byte; }
        public SqlByte(string column, string table)
            : base(NodeType.Column)
        {
            Type = SqlType.Byte;
            Table = table;
            Identity = NameIdentity.Get(Type, column);
        }
        public SqlByte(string parameterName, byte? value, ParameterDirection direction)
            : base(NodeType.Parameter)
        {
            Type = SqlType.Byte;
            Identity = NameIdentity.Get(Type, parameterName, direction);
            Value = value;
        }

        protected override SqlByte ArithmeticCore(ArithmeticOperator op, byte? value)
        {
            switch (op)
            {
                case ArithmeticOperator.Add: this.Value += value; break;
                case ArithmeticOperator.Divide: this.Value = (byte)(this.Value/value); break;
                case ArithmeticOperator.Multiply: this.Value *= value; break;
                case ArithmeticOperator.Subtract: this.Value -= value; break;
            }
            return this;
        }

        protected override SqlByte ModCore(byte? value)
        {
            this.Value = (byte)(this.Value % value);
            return this;
        }
       
        #region Operators

        #region Equals & NotEquals
        public static CriterionNode operator ==(SqlByte left, SqlByte right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlByte left, SqlByte right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(SqlByte left, byte? right)
        {
            return SqlByte.Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlByte left, byte? right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(byte? left, SqlByte right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(byte? left, SqlByte right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        #endregion

        #region GreaterThan & LessThan
        public static CriterionNode operator >(SqlByte left, SqlByte right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(SqlByte left, SqlByte right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        public static CriterionNode operator >(SqlByte left, byte? right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(SqlByte left, byte? right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        public static CriterionNode operator >(byte? left, SqlByte right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(byte? left, SqlByte right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        #endregion

        #region GreaterThanOrEquals & LessThanOrEquals
        public static CriterionNode operator >=(SqlByte left, SqlByte right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(SqlByte left, SqlByte right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        public static CriterionNode operator >=(SqlByte left, byte? right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(SqlByte left, byte? right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        public static CriterionNode operator >=(byte? left, SqlByte right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(byte? left, SqlByte right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        #endregion

        #region ++, + - * / %
        //public static ByteExpression operator ++(ByteExpression left)
        //{
        //    return Arithmetic(left, ArithmeticOperator.Add, 1);
        //}
        //public static ByteExpression operator --(ByteExpression left)
        //{
        //    return Arithmetic(left, ArithmeticOperator.Subtract, 1);
        //}

        public static SqlByte operator +(SqlByte left, SqlByte right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right);
        }

        public static SqlByte operator +(byte? left, SqlByte right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right);
        }

        public static SqlByte operator +(SqlByte left, byte? right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right);
        }

        public static SqlByte operator -(SqlByte left, SqlByte right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right);
        }

        public static SqlByte operator -(byte? left, SqlByte right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right);
        }

        public static SqlByte operator -(SqlByte left, byte? right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right);
        }

        public static SqlByte operator *(SqlByte left, SqlByte right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right);
        }

        public static SqlByte operator *(byte? left, SqlByte right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right);
        }

        public static SqlByte operator *(SqlByte left, byte? right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right);
        }

        public static SqlByte operator /(SqlByte left, SqlByte right)
        {
            return Arithmetic(left, ArithmeticOperator.Divide, right);
        }
        public static SqlByte operator /(byte? left, SqlByte right)
        {
            return Arithmetic(left, ArithmeticOperator.Divide, right);
        }
        public static SqlByte operator /(SqlByte left, byte? right)
        {
            return Arithmetic(left, ArithmeticOperator.Divide, right);
        }

        public static SqlByte operator %(SqlByte left, SqlByte right)
        {
            return InnerMod(left, right);
        }
        public static SqlByte operator %(byte? left, SqlByte right)
        {
            return InnerMod(left, right);
        }

        public static SqlByte operator %(SqlByte left, byte? right)
        {
            return InnerMod(left, right);
        }

        #endregion
        #endregion
    }

    public sealed partial class SqlInt16 : SqlNumber<SqlInt16, Int16?>
    {
        public SqlInt16() : base(NodeType.SqlObject) { Type = SqlType.Int16; }
        public SqlInt16(string column, string table)
            : base(NodeType.Column)
        {
            Type = SqlType.Int16;
            Table = table;
            Identity = NameIdentity.Get(Type, column);
        }
        public SqlInt16(string parameterName, Int16? value, ParameterDirection direction)
            : base(NodeType.Parameter)
        {
            Type = SqlType.Int16;
            Identity = NameIdentity.Get(Type, parameterName, direction);
            Value = value;
        }

        protected override SqlInt16 ArithmeticCore(ArithmeticOperator op, Int16? value)
        {
            switch (op)
            {
                case ArithmeticOperator.Add: this.Value += value; break;
                case ArithmeticOperator.Divide: this.Value = (Int16)(this.Value / value); break;
                case ArithmeticOperator.Multiply: this.Value *= value; break;
                case ArithmeticOperator.Subtract: this.Value -= value; break;
            }
            return this;
        }

        protected override SqlInt16 ModCore(short? value)
        {
            this.Value = (Int16)(this.Value % value);
            return this;
        }

        #region Operators

        #region Equals & NotEquals
        public static CriterionNode operator ==(SqlInt16 left, SqlInt16 right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlInt16 left, SqlInt16 right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(SqlInt16 left, Int16? right)
        {
            return SqlInt16.Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlInt16 left, Int16? right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(Int16? left, SqlInt16 right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(Int16? left, SqlInt16 right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        #endregion

        #region GreaterThan & LessThan
        public static CriterionNode operator >(SqlInt16 left, SqlInt16 right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(SqlInt16 left, SqlInt16 right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        public static CriterionNode operator >(SqlInt16 left, Int16? right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(SqlInt16 left, Int16? right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        public static CriterionNode operator >(Int16? left, SqlInt16 right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(Int16? left, SqlInt16 right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        #endregion

        #region GreaterThanOrEquals & LessThanOrEquals
        public static CriterionNode operator >=(SqlInt16 left, SqlInt16 right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(SqlInt16 left, SqlInt16 right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        public static CriterionNode operator >=(SqlInt16 left, Int16? right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(SqlInt16 left, Int16? right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        public static CriterionNode operator >=(Int16? left, SqlInt16 right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(Int16? left, SqlInt16 right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        #endregion

        #region + - * / %
        //public static Int16Expression operator ++(Int16Expression left)
        //{
        //    return Arithmetic(left, ArithmeticOperator.Add, 1);
        //}
        //public static Int16Expression operator --(Int16Expression left)
        //{
        //    return Arithmetic(left, ArithmeticOperator.Subtract, 1);
        //}
        public static SqlInt16 operator +(SqlInt16 left, SqlInt16 right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right);
        }

        public static SqlInt16 operator +(Int16? left, SqlInt16 right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right);
        }

        public static SqlInt16 operator +(SqlInt16 left, Int16? right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right);
        }

        public static SqlInt16 operator -(SqlInt16 left, SqlInt16 right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right);
        }
        public static SqlInt16 operator -(Int16? left, SqlInt16 right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right);
        }
        public static SqlInt16 operator -(SqlInt16 left, Int16? right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right);
        }

        public static SqlInt16 operator *(SqlInt16 left, SqlInt16 right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right);
        }

        public static SqlInt16 operator *(Int16? left, SqlInt16 right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right);
        }

        public static SqlInt16 operator *(SqlInt16 left, Int16? right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right);
        }

        public static SqlInt16 operator /(SqlInt16 left, SqlInt16 right)
        {
            return Arithmetic(left, ArithmeticOperator.Divide, right);
        }
        public static SqlInt16 operator /(Int16? left, SqlInt16 right)
        {
            return Arithmetic(left, ArithmeticOperator.Divide, right);
        }
        public static SqlInt16 operator /(SqlInt16 left, Int16? right)
        {
            return Arithmetic(left, ArithmeticOperator.Divide, right);
        }

        public static SqlInt16 operator %(SqlInt16 left, SqlInt16 right)
        {
            return InnerMod(left, right);
        }

        public static SqlInt16 operator %(Int16? left, SqlInt16 right)
        {
            return InnerMod(left, right);
        }
        public static SqlInt16 operator %(SqlInt16 left, Int16? right)
        {
            return InnerMod(left, right);
        }

        #endregion
        #endregion

        #region IConvertible
        public static CriterionNode operator >(SqlInt16 left, IConvertible right)
        {
            return Compare(left, CompareOperator.GreaterThan, right.ToInt16(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator <(SqlInt16 left, IConvertible right)
        {
            return Compare(left, CompareOperator.LessThan, right.ToInt16(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator >(IConvertible left, SqlInt16 right)
        {
            return Compare(left.ToInt16(NumberFormatInfo.CurrentInfo), CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(IConvertible left, SqlInt16 right)
        {
            return Compare(left.ToInt16(NumberFormatInfo.CurrentInfo), CompareOperator.LessThan, right);
        }
        public static CriterionNode operator >=(SqlInt16 left, IConvertible right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right.ToInt16(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator <=(SqlInt16 left, IConvertible right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right.ToInt16(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator >=(IConvertible left, SqlInt16 right)
        {
            return Compare(left.ToInt16(NumberFormatInfo.CurrentInfo), CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(IConvertible left, SqlInt16 right)
        {
            return Compare(left.ToInt16(NumberFormatInfo.CurrentInfo), CompareOperator.LessThanOrEquals, right);
        }
        public static SqlInt16 operator +(IConvertible left, SqlInt16 right)
        {
            return Arithmetic(left.ToInt16(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Add, right);
        }
        public static SqlInt16 operator +(SqlInt16 left, IConvertible right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right.ToInt16(NumberFormatInfo.CurrentInfo));
        }
        public static SqlInt16 operator -(IConvertible left, SqlInt16 right)
        {
            return Arithmetic(left.ToInt16(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Subtract, right);
        }
        public static SqlInt16 operator -(SqlInt16 left, IConvertible right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right.ToInt16(NumberFormatInfo.CurrentInfo));
        }
        public static SqlInt16 operator *(IConvertible left, SqlInt16 right)
        {
            return Arithmetic(left.ToInt16(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Multiply, right);
        }
        public static SqlInt16 operator *(SqlInt16 left, IConvertible right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right.ToInt16(NumberFormatInfo.CurrentInfo));
        }
        public static SqlInt16 operator /(IConvertible left, SqlInt16 right)
        {
            return Arithmetic(left.ToInt16(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Divide, right);
        }
        public static SqlInt16 operator %(IConvertible left, SqlInt16 right)
        {
            return InnerMod(left.ToInt16(NumberFormatInfo.CurrentInfo),  right);
        }
        public static SqlInt16 operator %(SqlInt16 left, IConvertible right)
        {
            return InnerMod(left,  right.ToInt16(NumberFormatInfo.CurrentInfo));
        }
        #endregion
    }

    public sealed partial class SqlInt32 : SqlNumber<SqlInt32, Int32?>
    {
        public SqlInt32() : base(NodeType.SqlObject) { Type = SqlType.Int32; }
        public SqlInt32(string column, string table)
            : base(NodeType.Column)
        {
            Type = SqlType.Int32;
            Table = table;
            Identity = NameIdentity.Get(Type, column);
        }
        public SqlInt32(string parameterName, Int32? value, ParameterDirection direction)
            : base(NodeType.Parameter)
        {
            Type = SqlType.Int32;
            Identity = NameIdentity.Get(Type, parameterName, direction);
            Value = value;
        }
        public SqlInt32(Int32? value) : this(ParameterName, value, ParameterDirection.Input) { }

        protected override SqlInt32 ArithmeticCore(ArithmeticOperator op, Int32? value)
        {
            switch (op)
            {
                case ArithmeticOperator.Add: this.Value += value; break;
                case ArithmeticOperator.Divide: this.Value = (Int32)(this.Value / value); break;
                case ArithmeticOperator.Multiply: this.Value *= value; break;
                case ArithmeticOperator.Subtract: this.Value -= value; break;
            }
            return this;
        }

        protected override SqlInt32 ModCore(int? value)
        {
            this.Value = (Int32)(this.Value % value);
            return this;
        }
        public SqlString ToChar()
        {
            return new SqlString 
            { 
                Expression = new FunctionExpression(FunctionView.ToChar,this.Clone() as INode),
            };
        }

        public SqlString ToNChar()
        {
            return new SqlString
            {
                Expression = new FunctionExpression(FunctionView.ToNChar, this.Clone() as INode),
            };
        }
        #region Operators

        #region Equals & NotEquals
        public static CriterionNode operator ==(SqlInt32 left, SqlInt32 right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlInt32 left, SqlInt32 right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(SqlInt32 left, Int32? right)
        {
            return SqlInt32.Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlInt32 left, Int32? right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(Int32? left, SqlInt32 right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(Int32? left, SqlInt32 right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        #endregion

        #region GreaterThan & LessThan
        public static CriterionNode operator >(SqlInt32 left, SqlInt32 right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(SqlInt32 left, SqlInt32 right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        public static CriterionNode operator >(SqlInt32 left, Int32? right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(SqlInt32 left, Int32? right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        public static CriterionNode operator >(Int32? left, SqlInt32 right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(Int32? left, SqlInt32 right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        #endregion

        #region GreaterThanOrEquals & LessThanOrEquals
        public static CriterionNode operator >=(SqlInt32 left, SqlInt32 right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(SqlInt32 left, SqlInt32 right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        public static CriterionNode operator >=(SqlInt32 left, Int32? right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(SqlInt32 left, Int32? right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        public static CriterionNode operator >=(Int32? left, SqlInt32 right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(Int32? left, SqlInt32 right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        #endregion

        #region + - * / %
       
        //public static Int32Expression operator ++(Int32Expression left)
        //{
        //    return Arithmetic(left, ArithmeticOperator.Add, 1);
        //}
        //public static Int32Expression operator --(Int32Expression left)
        //{
        //    return Arithmetic(left, ArithmeticOperator.Subtract, 1);
        //}
        public static SqlInt32 operator +(SqlInt32 left, SqlInt32 right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right);
        }

        public static SqlInt32 operator +(Int32? left, SqlInt32 right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right);
        }
        

        public static SqlInt32 operator +(SqlInt32 left, Int32? right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right);
        }

       

        public static SqlInt32 operator -(SqlInt32 left, SqlInt32 right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right);
        }

        public static SqlInt32 operator -(Int32? left, SqlInt32 right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right);
        }
       

        public static SqlInt32 operator -(SqlInt32 left, Int32? right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right);
        }
       

        public static SqlInt32 operator *(SqlInt32 left, SqlInt32 right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right);
        }

        public static SqlInt32 operator *(Int32? left, SqlInt32 right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right);
        }
       

        public static SqlInt32 operator *(SqlInt32 left, Int32? right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right);
        }
        

        public static SqlInt32 operator /(SqlInt32 left, SqlInt32 right)
        {
            return Arithmetic(left, ArithmeticOperator.Divide, right);
        }

        public static SqlInt32 operator /(Int32? left, SqlInt32 right)
        {
            return Arithmetic(left, ArithmeticOperator.Divide, right);
        }
       

        public static SqlInt32 operator /(SqlInt32 left, Int32? right)
        {
            return Arithmetic(left, ArithmeticOperator.Divide, right);
        }

        public static SqlInt32 operator %(SqlInt32 left, SqlInt32 right)
        {
            return InnerMod(left, right);
        }

        public static SqlInt32 operator %(Int32? left, SqlInt32 right)
        {
            return InnerMod(left, right);
        }
       

        public static SqlInt32 operator %(SqlInt32 left, Int32? right)
        {
            return InnerMod(left, right);
        }
        
        #endregion
        #endregion

        #region IConvertible
        public static CriterionNode operator >(SqlInt32 left, IConvertible right)
        {
            return Compare(left, CompareOperator.GreaterThan, right.ToInt32(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator <(SqlInt32 left, IConvertible right)
        {
            return Compare(left, CompareOperator.LessThan, right.ToInt32(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator >(IConvertible left, SqlInt32 right)
        {
            return Compare(left.ToInt32(NumberFormatInfo.CurrentInfo), CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(IConvertible left, SqlInt32 right)
        {
            return Compare(left.ToInt32(NumberFormatInfo.CurrentInfo), CompareOperator.LessThan, right);
        }
        public static CriterionNode operator >=(SqlInt32 left, IConvertible right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right.ToInt32(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator <=(SqlInt32 left, IConvertible right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right.ToInt32(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator >=(IConvertible left, SqlInt32 right)
        {
            return Compare(left.ToInt32(NumberFormatInfo.CurrentInfo), CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(IConvertible left, SqlInt32 right)
        {
            return Compare(left.ToInt32(NumberFormatInfo.CurrentInfo), CompareOperator.LessThanOrEquals, right);
        }
        public static SqlInt32 operator +(IConvertible left, SqlInt32 right)
        {
            return Arithmetic(left.ToInt32(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Add, right);
        }
        public static SqlInt32 operator +(SqlInt32 left, IConvertible right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right.ToInt32(NumberFormatInfo.CurrentInfo));
        }
        public static SqlInt32 operator -(IConvertible left, SqlInt32 right)
        {
            return Arithmetic(left.ToInt32(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Subtract, right);
        }
        public static SqlInt32 operator -(SqlInt32 left, IConvertible right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right.ToInt32(NumberFormatInfo.CurrentInfo));
        }
        public static SqlInt32 operator *(IConvertible left, SqlInt32 right)
        {
            return Arithmetic(left.ToInt32(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Multiply, right);
        }
        public static SqlInt32 operator *(SqlInt32 left, IConvertible right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right.ToInt32(NumberFormatInfo.CurrentInfo));
        }
        public static SqlInt32 operator /(IConvertible left, SqlInt32 right)
        {
            return Arithmetic(left.ToInt32(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Divide, right);
        }
        public static SqlInt32 operator %(IConvertible left, SqlInt32 right)
        {
            return InnerMod(left.ToInt32(NumberFormatInfo.CurrentInfo), right);
        }
        public static SqlInt32 operator %(SqlInt32 left, IConvertible right)
        {
            return InnerMod(left, right.ToInt32(NumberFormatInfo.CurrentInfo));
        }
        #endregion
    }

    public sealed partial class SqlInt64 : SqlNumber<SqlInt64, Int64?>
    {
        public SqlInt64() : base(NodeType.SqlObject) { Type = SqlType.Int64; }
        public SqlInt64(string column, string table)
            : base(NodeType.Column)
        {
            Type = SqlType.Int64;
            Table = table;
            Identity = NameIdentity.Get(Type, column);
        }
        public SqlInt64(string parameterName, Int64? value, ParameterDirection direction)
            : base(NodeType.Parameter)
        {
            Type = SqlType.Int64;
            Identity = NameIdentity.Get(Type, parameterName, direction);
            Value = value;
        }
        public SqlInt64(Int64? value) : this(ParameterName, value, ParameterDirection.Input) { }

        protected override SqlInt64 ArithmeticCore(ArithmeticOperator op, Int64? value)
        {
            switch (op)
            {
                case ArithmeticOperator.Add: this.Value += value; break;
                case ArithmeticOperator.Divide: this.Value = (Int64)(this.Value / value); break;
                case ArithmeticOperator.Multiply: this.Value *= value; break;
                case ArithmeticOperator.Subtract: this.Value -= value; break;
            }
            return this;
        }

        protected override SqlInt64 ModCore(long? value)
        {
            this.Value = (Int64)(this.Value % value);
            return this;
        }
        #region Operators

        #region Equals & NotEquals
        public static CriterionNode operator ==(SqlInt64 left, SqlInt64 right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlInt64 left, SqlInt64 right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(SqlInt64 left, Int64? right)
        {
            return SqlInt64.Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlInt64 left, Int64? right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(Int64? left, SqlInt64 right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(Int64? left, SqlInt64 right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        #endregion

        #region GreaterThan & LessThan
        public static CriterionNode operator >(SqlInt64 left, SqlInt64 right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(SqlInt64 left, SqlInt64 right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        public static CriterionNode operator >(SqlInt64 left, Int64? right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(SqlInt64 left, Int64? right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        public static CriterionNode operator >(Int64? left, SqlInt64 right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(Int64? left, SqlInt64 right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        #endregion

        #region GreaterThanOrEquals & LessThanOrEquals
        public static CriterionNode operator >=(SqlInt64 left, SqlInt64 right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(SqlInt64 left, SqlInt64 right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        public static CriterionNode operator >=(SqlInt64 left, Int64? right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(SqlInt64 left, Int64? right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        public static CriterionNode operator >=(Int64? left, SqlInt64 right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(Int64? left, SqlInt64 right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        #endregion

        #region + - * / %
        //public static Int64Expression operator ++(Int64Expression left)
        //{
        //    return Arithmetic(left, ArithmeticOperator.Add, 1);
        //}
        //public static Int64Expression operator --(Int64Expression left)
        //{
        //    return Arithmetic(left, ArithmeticOperator.Subtract, 1);
        //}
        public static SqlInt64 operator +(SqlInt64 left, SqlInt64 right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right);
        }

        public static SqlInt64 operator +(Int64? left, SqlInt64 right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right);
        }

        public static SqlInt64 operator +(SqlInt64 left, Int64? right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right);
        }

        public static SqlInt64 operator -(SqlInt64 left, SqlInt64 right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right);
        }
        public static SqlInt64 operator -(Int64? left, SqlInt64 right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right);
        }
        public static SqlInt64 operator -(SqlInt64 left, Int64? right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right);
        }

        public static SqlInt64 operator *(SqlInt64 left, SqlInt64 right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right);
        }

        public static SqlInt64 operator *(Int64? left, SqlInt64 right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right);
        }

        public static SqlInt64 operator *(SqlInt64 left, Int64? right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right);
        }

        public static SqlInt64 operator /(SqlInt64 left, SqlInt64 right)
        {
            return Arithmetic(left, ArithmeticOperator.Divide, right);
        }
        public static SqlInt64 operator /(Int64? left, SqlInt64 right)
        {
            return Arithmetic(left, ArithmeticOperator.Divide, right);
        }
        public static SqlInt64 operator /(SqlInt64 left, Int64? right)
        {
            return Arithmetic(left, ArithmeticOperator.Divide, right);
        }

        public static SqlInt64 operator %(SqlInt64 left, SqlInt64 right)
        {
            return InnerMod(left, right);
        }

        public static SqlInt64 operator %(Int64? left, SqlInt64 right)
        {
            return InnerMod(left, right);
        }
        public static SqlInt64 operator %(SqlInt64 left, Int64? right)
        {
            return InnerMod(left, right);
        }

        #endregion
        #endregion

        #region IConvertible
        public static CriterionNode operator >(SqlInt64 left, IConvertible right)
        {
            return Compare(left, CompareOperator.GreaterThan, right.ToInt64(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator <(SqlInt64 left, IConvertible right)
        {
            return Compare(left, CompareOperator.LessThan, right.ToInt64(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator >(IConvertible left, SqlInt64 right)
        {
            return Compare(left.ToInt64(NumberFormatInfo.CurrentInfo), CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(IConvertible left, SqlInt64 right)
        {
            return Compare(left.ToInt64(NumberFormatInfo.CurrentInfo), CompareOperator.LessThan, right);
        }
        public static CriterionNode operator >=(SqlInt64 left, IConvertible right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right.ToInt64(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator <=(SqlInt64 left, IConvertible right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right.ToInt64(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator >=(IConvertible left, SqlInt64 right)
        {
            return Compare(left.ToInt64(NumberFormatInfo.CurrentInfo), CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(IConvertible left, SqlInt64 right)
        {
            return Compare(left.ToInt64(NumberFormatInfo.CurrentInfo), CompareOperator.LessThanOrEquals, right);
        }
        public static SqlInt64 operator +(IConvertible left, SqlInt64 right)
        {
            return Arithmetic(left.ToInt64(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Add, right);
        }
        public static SqlInt64 operator +(SqlInt64 left, IConvertible right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right.ToInt64(NumberFormatInfo.CurrentInfo));
        }
        public static SqlInt64 operator -(IConvertible left, SqlInt64 right)
        {
            return Arithmetic(left.ToInt64(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Subtract, right);
        }
        public static SqlInt64 operator -(SqlInt64 left, IConvertible right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right.ToInt64(NumberFormatInfo.CurrentInfo));
        }
        public static SqlInt64 operator *(IConvertible left, SqlInt64 right)
        {
            return Arithmetic(left.ToInt64(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Multiply, right);
        }
        public static SqlInt64 operator *(SqlInt64 left, IConvertible right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right.ToInt64(NumberFormatInfo.CurrentInfo));
        }
        public static SqlInt64 operator /(IConvertible left, SqlInt64 right)
        {
            return Arithmetic(left.ToInt64(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Divide, right);
        }
        public static SqlInt64 operator %(IConvertible left, SqlInt64 right)
        {
            return InnerMod(left.ToInt64(NumberFormatInfo.CurrentInfo), right);
        }
        public static SqlInt64 operator %(SqlInt64 left, IConvertible right)
        {
            return InnerMod(left, right.ToInt64(NumberFormatInfo.CurrentInfo));
        }
        #endregion
    }

    public sealed partial class SqlDouble : SqlNumber<SqlDouble, Double?>
    {
        public SqlDouble() : base(NodeType.SqlObject) { Type = SqlType.Double; }
        public SqlDouble(string column, string table)
            : base(NodeType.Column)
        {
            Type = SqlType.Double;
            Table = table;
            Identity = NameIdentity.Get(Type, column);
        }
        public SqlDouble(string parameterName, Double? value, ParameterDirection direction)
            : base(NodeType.Parameter)
        {
            Type = SqlType.Double;
            Identity = NameIdentity.Get(Type, parameterName, direction);
            Value = value;
        }

        protected override SqlDouble ArithmeticCore(ArithmeticOperator op, Double? value)
        {
            switch (op)
            {
                case ArithmeticOperator.Add: this.Value += value; break;
                case ArithmeticOperator.Divide: this.Value = (Double)(this.Value / value); break;
                case ArithmeticOperator.Multiply: this.Value *= value; break;
                case ArithmeticOperator.Subtract: this.Value -= value; break;
            }
            return this;
        }

        protected override SqlDouble ModCore(double? value)
        {
            this.Value = (Double)(this.Value % value);
            return this;
        }

        private SqlDouble NoArgsFunc(string fnName)
        {
            return new SqlDouble { Expression = new FunctionExpression(FunctionView.Get(fnName), this.Expression ?? this) };
        }

        private SqlDouble ArgsFunc(string fnName,INode p)
        {
            return new SqlDouble { Expression = new FunctionExpression(FunctionView.Get(fnName), this.Expression ?? this,p) };
        }

        public SqlDouble Acos()
        {
            return NoArgsFunc(FunctionType.Math.Acos);
        }

        public SqlDouble Asin()
        {
            return NoArgsFunc(FunctionType.Math.Asin);
        }

        public SqlDouble Atan()
        {
            return NoArgsFunc(FunctionType.Math.Atan);
        }

        public SqlDouble Atan2(SqlDouble d)
        {
            return ArgsFunc(FunctionType.Math.Atan2, d);
        }

        public SqlDouble Atan2(double d)
        {
            return Atan2(CreateParameter(d));
        }

        public SqlDouble Ceiling()
        {
            return NoArgsFunc(FunctionType.Math.Ceiling);
        }

        public SqlDouble Cos()
        {
            return NoArgsFunc(FunctionType.Math.Cos);
        }

        //public DoubleExpression Cosh()
        //{
        //    return NoArgsFunc(FunctionType.Math.Cosh);
        //}

        public SqlDouble Exp()
        {
            return NoArgsFunc(FunctionType.Math.Exp);
        }

        public SqlDouble Floor()
        {
            return NoArgsFunc(FunctionType.Math.Floor);
        }


        public SqlDouble IEEERemainder()
        {
            return Log();
        }

        public SqlDouble Log()
        {
            return NoArgsFunc(FunctionType.Math.Log);
        }
        public SqlDouble Log10()
        {
            return NoArgsFunc(FunctionType.Math.Log10);
        }


        public SqlDouble Power(SqlDouble d)
        {
            return ArgsFunc(FunctionType.Math.Power, d);
        }

        public SqlDouble Power(double d)
        {
            return Power(CreateParameter(d));
        }

        public SqlDouble Round(SqlInt32 d)
        {
            return ArgsFunc(FunctionType.Math.Round, d);
        }

        public SqlDouble Round(Int32 d)
        {
            return Round(new SqlInt32(d));
        }
        public SqlDouble Round()
        {
            return Round(new SqlInt32(0));
        }
        public SqlDouble Sin()
        {
            return NoArgsFunc(FunctionType.Math.Sin);
        }
        //public DoubleExpression Sinh()
        //{
        //    return NoArgsFunc(FunctionType.Math.Sinh);
        //}
        public SqlDouble Sqrt()
        {
            return NoArgsFunc(FunctionType.Math.Sqrt);
        }
        public SqlDouble Tan()
        {
            return NoArgsFunc(FunctionType.Math.Tan);
        }
        public SqlDouble Tanh()
        {
            return NoArgsFunc(FunctionType.Math.Tanh);
        }
        public SqlDouble Truncate()
        {
            return NoArgsFunc(FunctionType.Math.Truncate);
        }
        #region Operators

        #region Equals & NotEquals
        public static CriterionNode operator ==(SqlDouble left, SqlDouble right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlDouble left, SqlDouble right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(SqlDouble left, Double? right)
        {
            return SqlDouble.Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlDouble left, Double? right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(Double? left, SqlDouble right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(Double? left, SqlDouble right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        #endregion

        #region GreaterThan & LessThan
        public static CriterionNode operator >(SqlDouble left, SqlDouble right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(SqlDouble left, SqlDouble right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        public static CriterionNode operator >(SqlDouble left, Double? right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(SqlDouble left, Double? right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        public static CriterionNode operator >(Double? left, SqlDouble right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(Double? left, SqlDouble right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        #endregion

        #region GreaterThanOrEquals & LessThanOrEquals
        public static CriterionNode operator >=(SqlDouble left, SqlDouble right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(SqlDouble left, SqlDouble right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        public static CriterionNode operator >=(SqlDouble left, Double? right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(SqlDouble left, Double? right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        public static CriterionNode operator >=(Double? left, SqlDouble right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(Double? left, SqlDouble right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        #endregion

        #region + - * / %
        //public static DoubleExpression operator ++(DoubleExpression left)
        //{
        //    return Arithmetic(left, ArithmeticOperator.Add, 1);
        //}
        //public static DoubleExpression operator --(DoubleExpression left)
        //{
        //    return Arithmetic(left, ArithmeticOperator.Subtract, 1);
        //}
        public static SqlDouble operator +(SqlDouble left, SqlDouble right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right);
        }

        public static SqlDouble operator +(Double? left, SqlDouble right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right);
        }

        public static SqlDouble operator +(SqlDouble left, Double? right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right);
        }

        public static SqlDouble operator -(SqlDouble left, SqlDouble right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right);
        }
        public static SqlDouble operator -(Double? left, SqlDouble right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right);
        }
        public static SqlDouble operator -(SqlDouble left, Double? right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right);
        }

        public static SqlDouble operator *(SqlDouble left, SqlDouble right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right);
        }

        public static SqlDouble operator *(Double? left, SqlDouble right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right);
        }

        public static SqlDouble operator *(SqlDouble left, Double? right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right);
        }

        public static SqlDouble operator /(SqlDouble left, SqlDouble right)
        {
            return Arithmetic(left, ArithmeticOperator.Divide, right);
        }
        public static SqlDouble operator /(Double? left, SqlDouble right)
        {
            return Arithmetic(left, ArithmeticOperator.Divide, right);
        }
        public static SqlDouble operator /(SqlDouble left, Double? right)
        {
            return Arithmetic(left, ArithmeticOperator.Divide, right);
        }

        public static SqlDouble operator %(SqlDouble left, SqlDouble right)
        {
            return InnerMod(left, right);
        }

        public static SqlDouble operator %(Double? left, SqlDouble right)
        {
            return InnerMod(left, right);
        }
        public static SqlDouble operator %(SqlDouble left, Double? right)
        {
            return InnerMod(left, right);
        }

        #endregion
        #endregion

        #region IConvertible
        public static CriterionNode operator >(SqlDouble left, IConvertible right)
        {
            return Compare(left, CompareOperator.GreaterThan, right.ToDouble(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator <(SqlDouble left, IConvertible right)
        {
            return Compare(left, CompareOperator.LessThan, right.ToDouble(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator >(IConvertible left, SqlDouble right)
        {
            return Compare(left.ToDouble(NumberFormatInfo.CurrentInfo), CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(IConvertible left, SqlDouble right)
        {
            return Compare(left.ToDouble(NumberFormatInfo.CurrentInfo), CompareOperator.LessThan, right);
        }
        public static CriterionNode operator >=(SqlDouble left, IConvertible right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right.ToDouble(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator <=(SqlDouble left, IConvertible right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right.ToDouble(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator >=(IConvertible left, SqlDouble right)
        {
            return Compare(left.ToDouble(NumberFormatInfo.CurrentInfo), CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(IConvertible left, SqlDouble right)
        {
            return Compare(left.ToDouble(NumberFormatInfo.CurrentInfo), CompareOperator.LessThanOrEquals, right);
        }
        public static SqlDouble operator +(IConvertible left, SqlDouble right)
        {
            return Arithmetic(left.ToDouble(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Add, right);
        }
        public static SqlDouble operator +(SqlDouble left, IConvertible right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right.ToDouble(NumberFormatInfo.CurrentInfo));
        }
        public static SqlDouble operator -(IConvertible left, SqlDouble right)
        {
            return Arithmetic(left.ToDouble(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Subtract, right);
        }
        public static SqlDouble operator -(SqlDouble left, IConvertible right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right.ToDouble(NumberFormatInfo.CurrentInfo));
        }
        public static SqlDouble operator *(IConvertible left, SqlDouble right)
        {
            return Arithmetic(left.ToDouble(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Multiply, right);
        }
        public static SqlDouble operator *(SqlDouble left, IConvertible right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right.ToDouble(NumberFormatInfo.CurrentInfo));
        }
        public static SqlDouble operator /(IConvertible left, SqlDouble right)
        {
            return Arithmetic(left.ToDouble(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Divide, right);
        }
        public static SqlDouble operator %(IConvertible left, SqlDouble right)
        {
            return InnerMod(left.ToDouble(NumberFormatInfo.CurrentInfo), right);
        }
        public static SqlDouble operator %(SqlDouble left, IConvertible right)
        {
            return InnerMod(left, right.ToDouble(NumberFormatInfo.CurrentInfo));
        }
        #endregion
    }

    public sealed partial class SqlDecimal : SqlNumber<SqlDecimal, Decimal?>
    {
        public SqlDecimal() : base(NodeType.SqlObject) { Type = SqlType.Decimal; }
        public SqlDecimal(string column, string table)
            : base(NodeType.Column)
        {
            Type = SqlType.Decimal;
            Table = table;
            Identity = NameIdentity.Get(Type, column);
        }
        public SqlDecimal(string column, string table, byte precision, byte scale)
            : base(NodeType.Column)
        {
            if (precision < 1
               || precision > MaxPrecision
                //|| scale < 0
               || scale > MaxScale
               || scale > precision)
                throw new ArgumentOutOfRangeException("Invalid numeric precision/scale.");

            Type = SqlType.GetSqlType(DbTypeCode.Decimal,precision,scale);
            Table = table;
            Identity = NameIdentity.Get(Type, column);
        }
        public SqlDecimal(string parameterName, Decimal? value, ParameterDirection direction)
            : base(NodeType.Parameter)
        {
            Type = SqlType.Decimal;
            Identity = NameIdentity.Get(Type, parameterName, direction);
            Value = value;
        }

        public SqlDecimal(string parameterName, Decimal? value, byte precision, byte scale, ParameterDirection direction)
            : base(NodeType.Parameter)
        {
            if (precision < 1
               || precision > MaxPrecision
                //|| scale < 0
               || scale > MaxScale
               || scale > precision)
                throw new ArgumentOutOfRangeException("Invalid numeric precision/scale.");

            Type = SqlType.GetSqlType(DbTypeCode.Decimal, precision, scale);
            Identity = NameIdentity.Get(Type, parameterName, direction);
            Value = value;
        }

        protected override SqlDecimal ArithmeticCore(ArithmeticOperator op, Decimal? value)
        {
            switch (op)
            {
                case ArithmeticOperator.Add: this.Value += value; break;
                case ArithmeticOperator.Divide: this.Value = (Decimal)(this.Value / value); break;
                case ArithmeticOperator.Multiply: this.Value *= value; break;
                case ArithmeticOperator.Subtract: this.Value -= value; break;
            }
            return this;
        }

        protected override SqlDecimal ModCore(decimal? value)
        {
            this.Value = (Decimal)(this.Value % value);
            return this;
        }
        private SqlDecimal NoArgsFunc(string fnName)
        {
            return new SqlDecimal { Expression = new FunctionExpression(FunctionView.Get(fnName), this.Expression ?? this) };
        }

        public SqlDecimal Ceiling()
        {
            return NoArgsFunc(FunctionType.Math.Ceiling);
        }
        public SqlDecimal Floor()
        {
            return NoArgsFunc(FunctionType.Math.Floor);
        }
        public SqlDecimal Round()
        {
            return NoArgsFunc(FunctionType.Math.Round);
        }
        public SqlDecimal Round(SqlInt32 d)
        {
            return new SqlDecimal { Expression = new FunctionExpression(FunctionView.Math.Round, this.Expression ?? this, d) };
        }

        public SqlDecimal Round(Int32 d)
        {
            return Round(new SqlInt32(d));
        }
        public SqlDecimal Truncate()
        {
            return NoArgsFunc(FunctionType.Math.Truncate);
        }
        #region Operators

        #region Equals & NotEquals
        public static CriterionNode operator ==(SqlDecimal left, SqlDecimal right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlDecimal left, SqlDecimal right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(SqlDecimal left, Decimal? right)
        {
            return SqlDecimal.Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlDecimal left, Decimal? right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(Decimal? left, SqlDecimal right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(Decimal? left, SqlDecimal right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        #endregion

        #region GreaterThan & LessThan
        public static CriterionNode operator >(SqlDecimal left, SqlDecimal right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(SqlDecimal left, SqlDecimal right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        public static CriterionNode operator >(SqlDecimal left, Decimal? right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(SqlDecimal left, Decimal? right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        public static CriterionNode operator >(Decimal? left, SqlDecimal right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(Decimal? left, SqlDecimal right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        #endregion

        #region GreaterThanOrEquals & LessThanOrEquals
        public static CriterionNode operator >=(SqlDecimal left, SqlDecimal right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(SqlDecimal left, SqlDecimal right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        public static CriterionNode operator >=(SqlDecimal left, Decimal? right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(SqlDecimal left, Decimal? right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        public static CriterionNode operator >=(Decimal? left, SqlDecimal right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(Decimal? left, SqlDecimal right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        #endregion

        #region + - * / %
        //public static DecimalExpression operator ++(DecimalExpression left)
        //{
        //    return Arithmetic(left, ArithmeticOperator.Add, 1);
        //}
        //public static DecimalExpression operator --(DecimalExpression left)
        //{
        //    return Arithmetic(left, ArithmeticOperator.Subtract, 1);
        //}
        public static SqlDecimal operator +(SqlDecimal left, SqlDecimal right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right);
        }

        public static SqlDecimal operator +(Decimal? left, SqlDecimal right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right);
        }

        public static SqlDecimal operator +(SqlDecimal left, Decimal? right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right);
        }

        public static SqlDecimal operator -(SqlDecimal left, SqlDecimal right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right);
        }
        public static SqlDecimal operator -(Decimal? left, SqlDecimal right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right);
        }
        public static SqlDecimal operator -(SqlDecimal left, Decimal? right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right);
        }

        public static SqlDecimal operator *(SqlDecimal left, SqlDecimal right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right);
        }

        public static SqlDecimal operator *(Decimal? left, SqlDecimal right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right);
        }

        public static SqlDecimal operator *(SqlDecimal left, Decimal? right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right);
        }

        public static SqlDecimal operator /(SqlDecimal left, SqlDecimal right)
        {
            return Arithmetic(left, ArithmeticOperator.Divide, right);
        }
        public static SqlDecimal operator /(Decimal? left, SqlDecimal right)
        {
            return Arithmetic(left, ArithmeticOperator.Divide, right);
        }
        public static SqlDecimal operator /(SqlDecimal left, Decimal? right)
        {
            return Arithmetic(left, ArithmeticOperator.Divide, right);
        }

        public static SqlDecimal operator %(SqlDecimal left, SqlDecimal right)
        {
            return InnerMod(left, right);
        }

        public static SqlDecimal operator %(Decimal? left, SqlDecimal right)
        {
            return InnerMod(left, right);
        }
        public static SqlDecimal operator %(SqlDecimal left, Decimal? right)
        {
            return InnerMod(left, right);
        }

        #endregion
        #endregion

        #region IConvertible
        public static CriterionNode operator >(SqlDecimal left, IConvertible right)
        {
            return Compare(left, CompareOperator.GreaterThan, right.ToDecimal(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator <(SqlDecimal left, IConvertible right)
        {
            return Compare(left, CompareOperator.LessThan, right.ToDecimal(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator >(IConvertible left, SqlDecimal right)
        {
            return Compare(left.ToDecimal(NumberFormatInfo.CurrentInfo), CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(IConvertible left, SqlDecimal right)
        {
            return Compare(left.ToDecimal(NumberFormatInfo.CurrentInfo), CompareOperator.LessThan, right);
        }
        public static CriterionNode operator >=(SqlDecimal left, IConvertible right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right.ToDecimal(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator <=(SqlDecimal left, IConvertible right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right.ToDecimal(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator >=(IConvertible left, SqlDecimal right)
        {
            return Compare(left.ToDecimal(NumberFormatInfo.CurrentInfo), CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(IConvertible left, SqlDecimal right)
        {
            return Compare(left.ToDecimal(NumberFormatInfo.CurrentInfo), CompareOperator.LessThanOrEquals, right);
        }
        public static SqlDecimal operator +(IConvertible left, SqlDecimal right)
        {
            return Arithmetic(left.ToDecimal(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Add, right);
        }
        public static SqlDecimal operator +(SqlDecimal left, IConvertible right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right.ToDecimal(NumberFormatInfo.CurrentInfo));
        }
        public static SqlDecimal operator -(IConvertible left, SqlDecimal right)
        {
            return Arithmetic(left.ToDecimal(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Subtract, right);
        }
        public static SqlDecimal operator -(SqlDecimal left, IConvertible right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right.ToDecimal(NumberFormatInfo.CurrentInfo));
        }
        public static SqlDecimal operator *(IConvertible left, SqlDecimal right)
        {
            return Arithmetic(left.ToDecimal(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Multiply, right);
        }
        public static SqlDecimal operator *(SqlDecimal left, IConvertible right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right.ToDecimal(NumberFormatInfo.CurrentInfo));
        }
        public static SqlDecimal operator /(IConvertible left, SqlDecimal right)
        {
            return Arithmetic(left.ToDecimal(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Divide, right);
        }
        public static SqlDecimal operator %(IConvertible left, SqlDecimal right)
        {
            return InnerMod(left.ToDecimal(NumberFormatInfo.CurrentInfo), right);
        }
        public static SqlDecimal operator %(SqlDecimal left, IConvertible right)
        {
            return InnerMod(left, right.ToDecimal(NumberFormatInfo.CurrentInfo));
        }
        #endregion
    }

    public sealed partial class SqlSingle : SqlNumber<SqlSingle, Single?>
    {
        public SqlSingle() : base(NodeType.SqlObject) { Type = SqlType.Single; }
        public SqlSingle(string column, string table)
            : base(NodeType.Column)
        {
            Type = SqlType.Single;
            Table = table;
            Identity = NameIdentity.Get(Type, column);
        }
        public SqlSingle(string parameterName, Single? value, ParameterDirection direction)
            : base(NodeType.Parameter)
        {
            Type = SqlType.Single;
            Identity = NameIdentity.Get(Type, parameterName, direction);
            Value = value;
        }

        protected override SqlSingle ArithmeticCore(ArithmeticOperator op, Single? value)
        {
            switch (op)
            {
                case ArithmeticOperator.Add: this.Value += value; break;
                case ArithmeticOperator.Divide: this.Value = (Single)(this.Value / value); break;
                case ArithmeticOperator.Multiply: this.Value *= value; break;
                case ArithmeticOperator.Subtract: this.Value -= value; break;
            }
            return this;
        }

        protected override SqlSingle ModCore(float? value)
        {
            this.Value = (Single)(this.Value % value);
            return this;
        }
        #region Operators

        #region Equals & NotEquals
        public static CriterionNode operator ==(SqlSingle left, SqlSingle right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlSingle left, SqlSingle right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(SqlSingle left, Single? right)
        {
            return SqlSingle.Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlSingle left, Single? right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(Single? left, SqlSingle right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(Single? left, SqlSingle right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        #endregion

        #region GreaterThan & LessThan
        public static CriterionNode operator >(SqlSingle left, SqlSingle right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(SqlSingle left, SqlSingle right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        public static CriterionNode operator >(SqlSingle left, Single? right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(SqlSingle left, Single? right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        public static CriterionNode operator >(Single? left, SqlSingle right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(Single? left, SqlSingle right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        #endregion

        #region GreaterThanOrEquals & LessThanOrEquals
        public static CriterionNode operator >=(SqlSingle left, SqlSingle right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(SqlSingle left, SqlSingle right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        public static CriterionNode operator >=(SqlSingle left, Single? right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(SqlSingle left, Single? right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        public static CriterionNode operator >=(Single? left, SqlSingle right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(Single? left, SqlSingle right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        #endregion

        #region + - * / %
        //public static SingleExpression operator ++(SingleExpression left)
        //{
        //    return Arithmetic(left, ArithmeticOperator.Add, 1);
        //}
        //public static SingleExpression operator --(SingleExpression left)
        //{
        //    return Arithmetic(left, ArithmeticOperator.Subtract, 1);
        //}
        public static SqlSingle operator +(SqlSingle left, SqlSingle right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right);
        }

        public static SqlSingle operator +(Single? left, SqlSingle right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right);
        }

        public static SqlSingle operator +(SqlSingle left, Single? right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right);
        }

        public static SqlSingle operator -(SqlSingle left, SqlSingle right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right);
        }
        public static SqlSingle operator -(Single? left, SqlSingle right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right);
        }
        public static SqlSingle operator -(SqlSingle left, Single? right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right);
        }

        public static SqlSingle operator *(SqlSingle left, SqlSingle right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right);
        }

        public static SqlSingle operator *(Single? left, SqlSingle right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right);
        }

        public static SqlSingle operator *(SqlSingle left, Single? right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right);
        }

        public static SqlSingle operator /(SqlSingle left, SqlSingle right)
        {
            return Arithmetic(left, ArithmeticOperator.Divide, right);
        }
        public static SqlSingle operator /(Single? left, SqlSingle right)
        {
            return Arithmetic(left, ArithmeticOperator.Divide, right);
        }
        public static SqlSingle operator /(SqlSingle left, Single? right)
        {
            return Arithmetic(left, ArithmeticOperator.Divide, right);
        }

        public static SqlSingle operator %(SqlSingle left, SqlSingle right)
        {
            return InnerMod(left, right);
        }

        public static SqlSingle operator %(Single? left, SqlSingle right)
        {
            return InnerMod(left, right);
        }
        public static SqlSingle operator %(SqlSingle left, Single? right)
        {
            return InnerMod(left, right);
        }

        #endregion
        #endregion

        #region IConvertible
        public static CriterionNode operator >(SqlSingle left, IConvertible right)
        {
            return Compare(left, CompareOperator.GreaterThan, right.ToSingle(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator <(SqlSingle left, IConvertible right)
        {
            return Compare(left, CompareOperator.LessThan, right.ToSingle(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator >(IConvertible left, SqlSingle right)
        {
            return Compare(left.ToSingle(NumberFormatInfo.CurrentInfo), CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(IConvertible left, SqlSingle right)
        {
            return Compare(left.ToSingle(NumberFormatInfo.CurrentInfo), CompareOperator.LessThan, right);
        }
        public static CriterionNode operator >=(SqlSingle left, IConvertible right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right.ToSingle(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator <=(SqlSingle left, IConvertible right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right.ToSingle(NumberFormatInfo.CurrentInfo));
        }

        public static CriterionNode operator >=(IConvertible left, SqlSingle right)
        {
            return Compare(left.ToSingle(NumberFormatInfo.CurrentInfo), CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(IConvertible left, SqlSingle right)
        {
            return Compare(left.ToSingle(NumberFormatInfo.CurrentInfo), CompareOperator.LessThanOrEquals, right);
        }
        public static SqlSingle operator +(IConvertible left, SqlSingle right)
        {
            return Arithmetic(left.ToSingle(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Add, right);
        }
        public static SqlSingle operator +(SqlSingle left, IConvertible right)
        {
            return Arithmetic(left, ArithmeticOperator.Add, right.ToSingle(NumberFormatInfo.CurrentInfo));
        }
        public static SqlSingle operator -(IConvertible left, SqlSingle right)
        {
            return Arithmetic(left.ToSingle(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Subtract, right);
        }
        public static SqlSingle operator -(SqlSingle left, IConvertible right)
        {
            return Arithmetic(left, ArithmeticOperator.Subtract, right.ToSingle(NumberFormatInfo.CurrentInfo));
        }
        public static SqlSingle operator *(IConvertible left, SqlSingle right)
        {
            return Arithmetic(left.ToSingle(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Multiply, right);
        }
        public static SqlSingle operator *(SqlSingle left, IConvertible right)
        {
            return Arithmetic(left, ArithmeticOperator.Multiply, right.ToSingle(NumberFormatInfo.CurrentInfo));
        }
        public static SqlSingle operator /(IConvertible left, SqlSingle right)
        {
            return Arithmetic(left.ToSingle(NumberFormatInfo.CurrentInfo), ArithmeticOperator.Divide, right);
        }
        public static SqlSingle operator %(IConvertible left, SqlSingle right)
        {
            return InnerMod(left.ToSingle(NumberFormatInfo.CurrentInfo), right);
        }
        public static SqlSingle operator %(SqlSingle left, IConvertible right)
        {
            return InnerMod(left, right.ToSingle(NumberFormatInfo.CurrentInfo));
        }
        #endregion
    }

    public sealed partial class SqlString : SqlObject<SqlString, string>
    {
         public SqlString() : base(NodeType.SqlObject) { Type = SqlType.String; }
         public SqlString(string column, string table,int? size)
            : base(NodeType.Column)
        {
            Type = size.HasValue? SqlType.GetString(size.Value) : SqlType.String;
            Table = table;
            Identity = NameIdentity.Get(Type, column);
        }
         public SqlString(string column, string table)
             : this(column,table,null)
         {
         }
        public SqlString(string parameterName, String value, ParameterDirection direction)
            : base(NodeType.Parameter)
        {
            Type = SqlType.String;
            Identity = NameIdentity.Get(Type, parameterName, direction);
            Value = value;
        }

        protected override SqlString CreateParameter(String value)
        {
            return new SqlString(ParameterName, value, ParameterDirection.Input);
        }

        public new string Value
        {
            get { return base.Value as string; }
            internal set { base.Value = value; }
        }
        #region Equals & NotEquals
        public static CriterionNode operator ==(SqlString left, SqlString right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlString left, SqlString right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(SqlString left, string right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlString left, string right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(string left, SqlString right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(string left, SqlString right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        #endregion

        public static CriterionNode operator %(SqlString left, string right)
        {
            if (object.ReferenceEquals(null, left))
                throw new ArgumentNullException("left");
            return left.Contains(right);
        }
        public static CriterionNode operator %(SqlString left, SqlString right)
        {
            if (object.ReferenceEquals(null, left))
                throw new ArgumentNullException("left");
            return left.Contains(right);
        }
        public static SqlString operator +(SqlString left, string right)
        {
            if (object.ReferenceEquals(null, left))
                throw new ArgumentNullException("left");
            return left.Concat(right);
        }
        public static SqlString operator +(string left, SqlString right)
        {
            if (object.ReferenceEquals(null, right))
                throw new ArgumentNullException("right");
            return right.CreateParameter(left).Concat(right);
        }
        public static SqlString operator +(SqlString left, SqlString right)
        {
            if (object.ReferenceEquals(null, left))
                return right;
            if (object.ReferenceEquals(null, right))
                return left;

            return left.Concat(right);
        }

        public CriterionNode StartsWith(string str)
        {
            
            return Contains(CreateParameter(str + "%"));
        }
       
        public CriterionNode EndsWith(string str)
        {
            return Contains(CreateParameter("%"+str));
        }
       
        public CriterionNode Contains(string str)
        {
            return Contains(CreateParameter("%" + str + "%"));
        }
        public CriterionNode Contains(SqlString str)
        {
            return new LikeNode(this.Expression ?? this, str);
        }

        public CriterionNode IsNullOrEmpty()
        {
            return new IsNullOrEmptyNode(this.Expression ?? this);
        }

        public SqlString Lower()
        {
            return new SqlString { Expression = new FunctionExpression(FunctionView.String.Lower, this.Expression??this) };
        }
        public SqlString Upper()
        {
            return new SqlString { Expression = new FunctionExpression(FunctionView.String.Upper, this.Expression ?? this) };
        }

        public SqlString Trim()
        {
            return new SqlString { Expression = new FunctionExpression(FunctionView.String.Trim, this.Expression ?? this) };
        }
        public SqlString TrimStart()
        {
            return new SqlString { Expression = new FunctionExpression(FunctionView.String.LTrim, this.Expression ?? this) };
        }
        public SqlString TrimEnd()
        {
            return new SqlString { Expression = new FunctionExpression(FunctionView.String.RTrim, this.Expression ?? this) };
        }

        public SqlString SubString(int start,int length)
        {
            return SubString(new SqlInt32(start), new SqlInt32(length));
        }
        public SqlString SubString(int start, SqlInt32 length)
        {
            return SubString(new SqlInt32(start), length);
        }
        public SqlString SubString(SqlInt32 start, int length)
        {
            return SubString(start, new SqlInt32(length));
        }
        public SqlString SubString(SqlInt32 start, SqlInt32 length)
        {
            start.Value = start.Value + 1;
            return new SqlString { Expression = new FunctionExpression(FunctionView.String.SubString, this.Expression ?? this, start, length) };
        }

        public SqlInt32 IndexOf(string value)
        {
            return IndexOf(CreateParameter(value));
        }
        public SqlInt32 IndexOf(SqlString value)
        {
            return new SqlInt32 { Expression = new FunctionExpression(FunctionView.String.IndexOf, this.Expression ?? this, value) };
        }

        public SqlInt32 IndexOf(string value,int start)
        {
            return IndexOf(CreateParameter(value), new SqlInt32(start));
        }
        public SqlInt32 IndexOf(SqlString value, SqlInt32 start)
        {
            start.Value = start.Value + 1;
            return new SqlInt32 { Expression = new FunctionExpression(FunctionView.String.IndexOf, this.Expression ?? this, value, start) };
        }

        public SqlString Replace(string old, string @new)
        {
            return Replace(CreateParameter(old), CreateParameter(@new));
        }
        public SqlString Replace(SqlString old, string @new)
        {
            return Replace(old, CreateParameter(@new));
        }
        public SqlString Replace(string old, SqlString @new)
        {
            return Replace(CreateParameter(old), @new);
        }
        public SqlString Replace(SqlString old, SqlString @new)
        {
            var expr = new SqlString();
            expr.Expression = new FunctionExpression(FunctionView.String.Replace, this.Expression ?? this, old, @new);
            return expr;
        }


        public SqlString Remove(int start, int length)
        {
            return Remove(new SqlInt32(start), new SqlInt32(length));
        }
        public SqlString Remove(int start, SqlInt32 length)
        {
            return Remove(new SqlInt32(start), length);
        }
        public SqlString Remove(SqlInt32 start, int length)
        {
            return Remove(start, new SqlInt32(length));
        }
        public SqlString Remove(SqlInt32 start, SqlInt32 length)
        {

            start.Value = start.Value + 1;
            var expr = new SqlString();
            expr.Expression = new FunctionExpression(FunctionView.String.Remove, this.Expression ?? this, start, length);
            return expr;
        }

        public SqlString Remove(Int32 start)
        {
            return Remove(new SqlInt32(start));
        }
        public SqlString Remove(SqlInt32 start)
        {
            start.Value = start.Value + 1;
            var expr = new SqlString();
            expr.Expression = new FunctionExpression(FunctionView.String.Remove, this.Expression ?? this, start);
            return expr;
        }

        public SqlInt32 Length
        {
            get
            {
                if (IsParameter)
                    return new SqlInt32(string.IsNullOrEmpty(Value) ? 0 : Value.Length);
                var fn = new FunctionExpression(FunctionView.String.Length, this.Expression ?? this);
                return new SqlInt32 { Expression = fn };
            }
        }

        public SqlString Left(int length)
        {
            if (IsParameter && !string.IsNullOrEmpty(Value))
            {
                Value = Value.Substring(0,length);
                return this;
            }
            return Left(new SqlInt32(length));
        }
        public SqlString Left(SqlInt32 length)
        {
            var expr = new SqlString();
            expr.Expression = new FunctionExpression(FunctionView.String.Left, this.Expression ?? this, length);
            return expr;
        }
        public SqlString Right(int start)
        {
            if (IsParameter && !string.IsNullOrEmpty(Value))
            {
                Value = Value.Substring(start);
                return this;
            }
            return Right(new SqlInt32(start));
        }
        public SqlString Right(SqlInt32 start)
        {
           
            start.Value = start.Value + 1;
            var expr = new SqlString();
            expr.Expression = new FunctionExpression(FunctionView.String.Right, this.Expression ?? this, start);
            return expr;
        }

        public SqlString Concat(string str)
        {
            if (!string.IsNullOrEmpty(Value))
            {
                Value = Value + str;
                return this;
            }

            return new SqlString { Expression = new FunctionExpression(FunctionView.String.Concat, this.Expression ?? this, CreateParameter(str)) };
        }
        public SqlString Concat(SqlString str)
        {
            if (!string.IsNullOrEmpty(str.Value))
                return Concat(str.Value);

            return new SqlString { Expression = new FunctionExpression(FunctionView.String.Concat, this.Expression ?? this, str) };
        }
    }
    public sealed partial class SqlAnsiString : SqlObject<SqlAnsiString, string>
    {
        public SqlAnsiString() : base(NodeType.SqlObject) { Type = SqlType.AnsiString; }
        public SqlAnsiString(string column, string table,int? size)
            : base(NodeType.Column)
        {
            Type = size.HasValue ? SqlType.GetAnsiString(size.Value) : SqlType.AnsiString;
            Table = table;
            Identity = NameIdentity.Get(Type, column);
        }
         public SqlAnsiString(string column, string table)
             : this(column,table,null)
         {
         }
        public SqlAnsiString(string parameterName, String value, ParameterDirection direction)
            : base(NodeType.Parameter)
        {
            Type = SqlType.AnsiString;
            Identity = NameIdentity.Get(Type, parameterName, direction);
            Value = value;
        }

        protected override SqlAnsiString CreateParameter(String value)
        {
            return new SqlAnsiString(ParameterName, value, ParameterDirection.Input);
        }

        public new string Value
        {
            get { return base.Value as string; }
            internal set { base.Value = value; }
        }

        #region Equals & NotEquals
        public static CriterionNode operator ==(SqlAnsiString left, SqlAnsiString right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlAnsiString left, SqlAnsiString right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(SqlAnsiString left, string right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlAnsiString left, string right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(string left, SqlAnsiString right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(string left, SqlAnsiString right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        #endregion

        public static CriterionNode operator %(SqlAnsiString left, string right)
        {
            if (object.ReferenceEquals(null, left))
                throw new ArgumentNullException("left");
            return left.Contains(right);
        }
        public static CriterionNode operator %(SqlAnsiString left, SqlAnsiString right)
        {
            if (object.ReferenceEquals(null, left))
                throw new ArgumentNullException("left");
            return left.Contains(right);
        }
        public static SqlAnsiString operator +(SqlAnsiString left, string right)
        {
            if (object.ReferenceEquals(null, left))
                throw new ArgumentNullException("left");
            return left.Concat(right);
        }
        public static SqlAnsiString operator +(string left, SqlAnsiString right)
        {
            if (object.ReferenceEquals(null, right))
                throw new ArgumentNullException("right");
            return right.CreateParameter(left).Concat(right);
        }
        public static SqlAnsiString operator +(SqlAnsiString left, SqlAnsiString right)
        {
            if (object.ReferenceEquals(null, left))
                return right;
            if (object.ReferenceEquals(null, right))
                return left;

            return left.Concat(right);
        }

        public CriterionNode StartsWith(string str)
        {
            return Contains(CreateParameter(str + "%"));
        }

        public CriterionNode EndsWith(string str)
        {
            return Contains(CreateParameter("%" + str));
        }

        public CriterionNode Contains(string str)
        {
            return Contains(CreateParameter("%" + str + "%"));
        }
        public CriterionNode Contains(SqlAnsiString str)
        {
            return new LikeNode(this.Expression ?? this, str);
        }

        public CriterionNode IsNullOrEmpty()
        {
            return new IsNullOrEmptyNode(this.Expression ?? this);
        }

        public SqlAnsiString Lower()
        {
            return new SqlAnsiString { Expression = new FunctionExpression(FunctionView.String.Lower, this.Expression ?? this) };
        }
        public SqlAnsiString Upper()
        {
            return new SqlAnsiString { Expression = new FunctionExpression(FunctionView.String.Upper, this.Expression ?? this) };
        }

        public SqlAnsiString Trim()
        {
            return new SqlAnsiString { Expression = new FunctionExpression(FunctionView.String.Trim, this.Expression ?? this) };
        }
        public SqlAnsiString TrimStart()
        {
            return new SqlAnsiString { Expression = new FunctionExpression(FunctionView.String.LTrim, this.Expression ?? this) };
        }
        public SqlAnsiString TrimEnd()
        {
            return new SqlAnsiString { Expression = new FunctionExpression(FunctionView.String.RTrim, this.Expression ?? this) };
        }

        public SqlAnsiString SubString(int start, int length)
        {
            return SubString(new SqlInt32(start), new SqlInt32(length));
        }
        public SqlAnsiString SubString(int start, SqlInt32 length)
        {
            return SubString(new SqlInt32(start), length);
        }
        public SqlAnsiString SubString(SqlInt32 start, int length)
        {
            return SubString(start, new SqlInt32(length));
        }
        public SqlAnsiString SubString(SqlInt32 start, SqlInt32 length)
        {
            start.Value = start.Value + 1;
            return new SqlAnsiString { Expression = new FunctionExpression(FunctionView.String.SubString, this.Expression ?? this, start, length) };
        }

        public SqlInt32 IndexOf(string value)
        {
            return IndexOf(CreateParameter(value));
        }
        public SqlInt32 IndexOf(SqlAnsiString value)
        {
            return new SqlInt32 { Expression = new FunctionExpression(FunctionView.String.IndexOf, this, value) };
        }

        public SqlInt32 IndexOf(string value, int start)
        {
            return IndexOf(CreateParameter(value), new SqlInt32(start));
        }
        public SqlInt32 IndexOf(SqlAnsiString value, SqlInt32 start)
        {
            start.Value = start.Value + 1;
            return new SqlInt32 { Expression = new FunctionExpression(FunctionView.String.IndexOf, this.Expression ?? this, value, start) };
        }

        public SqlAnsiString Replace(string old, string @new)
        {
            return Replace(CreateParameter(old), CreateParameter(@new));
        }
        public SqlAnsiString Replace(SqlAnsiString old, string @new)
        {
            return Replace(old, CreateParameter(@new));
        }
        public SqlAnsiString Replace(string old, SqlAnsiString @new)
        {
            return Replace(CreateParameter(old), @new);
        }
        public SqlAnsiString Replace(SqlAnsiString old, SqlAnsiString @new)
        {
            var expr = new SqlAnsiString();
            expr.Expression = new FunctionExpression(FunctionView.String.Replace, this.Expression ?? this, old, @new);
            return expr;
        }


        public SqlAnsiString Remove(int start, int length)
        {
            return Remove(new SqlInt32(start), new SqlInt32(length));
        }
        public SqlAnsiString Remove(int start, SqlInt32 length)
        {
            return Remove(new SqlInt32(start), length);
        }
        public SqlAnsiString Remove(SqlInt32 start, int length)
        {
            return Remove(start, new SqlInt32(length));
        }
        public SqlAnsiString Remove(SqlInt32 start, SqlInt32 length)
        {

            start.Value = start.Value + 1;
            var expr = new SqlAnsiString();
            expr.Expression = new FunctionExpression(FunctionView.String.Remove, this.Expression ?? this, start, length);
            return expr;
        }

        public SqlAnsiString Remove(Int32 start)
        {
            return Remove(new SqlInt32(start));
        }
        public SqlAnsiString Remove(SqlInt32 start)
        {
            start.Value = start.Value + 1;
            var expr = new SqlAnsiString();
            expr.Expression = new FunctionExpression(FunctionView.String.Remove, this.Expression ?? this, start);
            return expr;
        }

        public SqlInt32 Length
        {
            get
            {
                var fn = new FunctionExpression(FunctionView.String.Length, this.Expression ?? this);
                return new SqlInt32 { Expression = fn };
            }
        }

        public SqlAnsiString Left(int length)
        {
            return Left(new SqlInt32(length));
        }
        public SqlAnsiString Left(SqlInt32 length)
        {
            var expr = new SqlAnsiString();
            expr.Expression = new FunctionExpression(FunctionView.String.Left, this.Expression ?? this, length);
            return expr;
        }
        public SqlAnsiString Right(int start)
        {
            return Right(new SqlInt32(start));
        }
        public SqlAnsiString Right(SqlInt32 start)
        {

            start.Value = start.Value + 1;
            var expr = new SqlAnsiString();
            expr.Expression = new FunctionExpression(FunctionView.String.Right, this.Expression ?? this, start);
            return expr;
        }

        public SqlAnsiString Concat(string str)
        {
            if (!string.IsNullOrEmpty(Value))
            {
                Value = Value + str;
                return this;
            }

            return new SqlAnsiString { Expression = new FunctionExpression(FunctionView.String.Concat, this.Expression ?? this, CreateParameter(str)) };
        }
        public SqlAnsiString Concat(SqlAnsiString str)
        {
            if (!string.IsNullOrEmpty(str.Value))
                return Concat(str.Value);

            return new SqlAnsiString { Expression = new FunctionExpression(FunctionView.String.Concat, this.Expression ?? this, str) };
        }
    }
    public sealed partial class SqlClob : SqlObject<SqlClob, string>
    {
        public SqlClob() : base(NodeType.SqlObject) { Type = SqlType.Clob; }
        public SqlClob(string column, string table)
            : base(NodeType.Column)
        {
            Type = SqlType.Clob;
            Table = table;
            Identity = NameIdentity.Get(Type, column);
        }
        public SqlClob(string parameterName, String value, ParameterDirection direction)
            : base(NodeType.Parameter)
        {
            Type = SqlType.Clob;
            Identity = NameIdentity.Get(Type, parameterName, direction);
            Value = value;
        }

        protected override SqlClob CreateParameter(String value)
        {
            return new SqlClob(ParameterName, value, ParameterDirection.Input);
        }

        public new string Value
        {
            get { return base.Value as string; }
            internal set { base.Value = value; }
        }

        #region Equals & NotEquals
        public static CriterionNode operator ==(SqlClob left, SqlClob right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlClob left, SqlClob right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(SqlClob left, string right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlClob left, string right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(string left, SqlClob right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(string left, SqlClob right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        #endregion

        public static CriterionNode operator %(SqlClob left, string right)
        {
            if (object.ReferenceEquals(null, left))
                throw new ArgumentNullException("left");
            return left.Contains(right);
        }
        public static CriterionNode operator %(SqlClob left, SqlClob right)
        {
            if (object.ReferenceEquals(null, left))
                throw new ArgumentNullException("left");
            return left.Contains(right);
        }
        public static SqlClob operator +(SqlClob left, string right)
        {
            if (object.ReferenceEquals(null, left))
                throw new ArgumentNullException("left");
            return left.Concat(right);
        }
        public static SqlClob operator +(string left, SqlClob right)
        {
            if (object.ReferenceEquals(null, right))
                throw new ArgumentNullException("right");
            return right.CreateParameter(left).Concat(right);
        }
        public static SqlClob operator +(SqlClob left, SqlClob right)
        {
            if (object.ReferenceEquals(null, left))
                return right;
            if (object.ReferenceEquals(null, right))
                return left;

            return left.Concat(right);
        }

        public CriterionNode StartsWith(string str)
        {
            return Contains(CreateParameter(str + "%"));
        }

        public CriterionNode EndsWith(string str)
        {
            return Contains(CreateParameter("%" + str));
        }

        public CriterionNode Contains(string str)
        {
            return Contains(CreateParameter("%" + str + "%"));
        }
        public CriterionNode Contains(SqlClob str)
        {
            return new LikeNode(this.Expression ?? this, str);
        }

        public CriterionNode IsNullOrEmpty()
        {
            return new IsNullOrEmptyNode(this.Expression ?? this);
        }

        public SqlClob Lower()
        {
            return new SqlClob { Expression = new FunctionExpression(FunctionView.String.Lower, this.Expression ?? this) };
        }
        public SqlClob Upper()
        {
            return new SqlClob { Expression = new FunctionExpression(FunctionView.String.Upper, this.Expression ?? this) };
        }

        public SqlClob Trim()
        {
            return new SqlClob { Expression = new FunctionExpression(FunctionView.String.Trim, this.Expression ?? this) };
        }
        public SqlClob TrimStart()
        {
            return new SqlClob { Expression = new FunctionExpression(FunctionView.String.LTrim, this.Expression ?? this) };
        }
        public SqlClob TrimEnd()
        {
            return new SqlClob { Expression = new FunctionExpression(FunctionView.String.RTrim, this.Expression ?? this) };
        }

        public SqlClob SubString(int start, int length)
        {
            return SubString(new SqlInt32(start), new SqlInt32(length));
        }
        public SqlClob SubString(int start, SqlInt32 length)
        {
            return SubString(new SqlInt32(start), length);
        }
        public SqlClob SubString(SqlInt32 start, int length)
        {
            return SubString(start, new SqlInt32(length));
        }
        public SqlClob SubString(SqlInt32 start, SqlInt32 length)
        {
            start.Value = start.Value + 1;
            return new SqlClob { Expression = new FunctionExpression(FunctionView.String.SubString, this.Expression ?? this, start, length) };
        }

        public SqlInt32 IndexOf(string value)
        {
            return IndexOf(CreateParameter(value));
        }
        public SqlInt32 IndexOf(SqlClob value)
        {
            return new SqlInt32 { Expression = new FunctionExpression(FunctionView.String.IndexOf, this.Expression ?? this, value) };
        }

        public SqlInt32 IndexOf(string value, int start)
        {
            return IndexOf(CreateParameter(value), new SqlInt32(start));
        }
        public SqlInt32 IndexOf(SqlClob value, SqlInt32 start)
        {
            start.Value = start.Value + 1;
            return new SqlInt32 { Expression = new FunctionExpression(FunctionView.String.IndexOf, this.Expression ?? this, value, start) };
        }

        public SqlClob Replace(string old, string @new)
        {
            return Replace(CreateParameter(old), CreateParameter(@new));
        }
        public SqlClob Replace(SqlClob old, string @new)
        {
            return Replace(old, CreateParameter(@new));
        }
        public SqlClob Replace(string old, SqlClob @new)
        {
            return Replace(CreateParameter(old), @new);
        }
        public SqlClob Replace(SqlClob old, SqlClob @new)
        {
            var expr = new SqlClob();
            expr.Expression = new FunctionExpression(FunctionView.String.Replace, this.Expression ?? this, old, @new);
            return expr;
        }


        public SqlClob Remove(int start, int length)
        {
            return Remove(new SqlInt32(start), new SqlInt32(length));
        }
        public SqlClob Remove(int start, SqlInt32 length)
        {
            return Remove(new SqlInt32(start), length);
        }
        public SqlClob Remove(SqlInt32 start, int length)
        {
            return Remove(start, new SqlInt32(length));
        }
        public SqlClob Remove(SqlInt32 start, SqlInt32 length)
        {

            start.Value = start.Value + 1;
            var expr = new SqlClob();
            expr.Expression = new FunctionExpression(FunctionView.String.Remove, this.Expression ?? this, start, length);
            return expr;
        }

        public SqlClob Remove(Int32 start)
        {
            return Remove(new SqlInt32(start));
        }
        public SqlClob Remove(SqlInt32 start)
        {
            start.Value = start.Value + 1;
            var expr = new SqlClob();
            expr.Expression = new FunctionExpression(FunctionView.String.Remove, this.Expression ?? this, start);
            return expr;
        }

        public SqlInt32 Length
        {
            get
            {
                var fn = new FunctionExpression(FunctionView.String.Length, this.Expression ?? this);
                return new SqlInt32 { Expression = fn };
            }
        }

        public SqlClob Left(int length)
        {
            return Left(new SqlInt32(length));
        }
        public SqlClob Left(SqlInt32 length)
        {
            var expr = new SqlClob();
            expr.Expression = new FunctionExpression(FunctionView.String.Left, this.Expression ?? this, length);
            return expr;
        }
        public SqlClob Right(int start)
        {
            return Right(new SqlInt32(start));
        }
        public SqlClob Right(SqlInt32 start)
        {

            start.Value = start.Value + 1;
            var expr = new SqlClob();
            expr.Expression = new FunctionExpression(FunctionView.String.Right, this.Expression ?? this, start);
            return expr;
        }

        public SqlClob Concat(string str)
        {
            if (!string.IsNullOrEmpty(Value))
            {
                Value = Value + str;
                return this;
            }

            return new SqlClob { Expression = new FunctionExpression(FunctionView.String.Concat, this.Expression ?? this, CreateParameter(str)) };
        }
        public SqlClob Concat(SqlClob str)
        {
            if (!string.IsNullOrEmpty(str.Value))
                return Concat(str.Value);

            return new SqlClob { Expression = new FunctionExpression(FunctionView.String.Concat, this.Expression ?? this, str) };
        }
    }
    public sealed partial class SqlNClob : SqlObject<SqlNClob, string>
    {
        public SqlNClob() : base(NodeType.SqlObject) { Type = SqlType.NClob; }
        public SqlNClob(string column, string table)
            : base(NodeType.Column)
        {
            Type = SqlType.NClob;
            Table = table;
            Identity = NameIdentity.Get(Type, column);
        }
        public SqlNClob(string parameterName, String value, ParameterDirection direction)
            : base(NodeType.Parameter)
        {
            Type = SqlType.NClob;
            Identity = NameIdentity.Get(Type, parameterName, direction);
            Value = value;
        }

        protected override SqlNClob CreateParameter(String value)
        {
            return new SqlNClob(ParameterName, value, ParameterDirection.Input);
        }

        public new string Value
        {
            get { return base.Value as string; }
            internal set { base.Value = value; }
        }

        #region Equals & NotEquals
        public static CriterionNode operator ==(SqlNClob left, SqlNClob right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlNClob left, SqlNClob right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(SqlNClob left, string right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlNClob left, string right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(string left, SqlNClob right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(string left, SqlNClob right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        #endregion

        public static CriterionNode operator %(SqlNClob left, string right)
        {
            if (object.ReferenceEquals(null, left))
                throw new ArgumentNullException("left");
            return left.Contains(right);
        }
        public static CriterionNode operator %(SqlNClob left, SqlNClob right)
        {
            if (object.ReferenceEquals(null, left))
                throw new ArgumentNullException("left");
            return left.Contains(right);
        }
        public static SqlNClob operator +(SqlNClob left, string right)
        {
            if (object.ReferenceEquals(null, left))
                throw new ArgumentNullException("left");
            return left.Concat(right);
        }
        public static SqlNClob operator +(string left, SqlNClob right)
        {
            if (object.ReferenceEquals(null, right))
                throw new ArgumentNullException("right");
            return right.CreateParameter(left).Concat(right);
        }
        public static SqlNClob operator +(SqlNClob left, SqlNClob right)
        {
            if (object.ReferenceEquals(null, left))
                return right;
            if (object.ReferenceEquals(null, right))
                return left;

            return left.Concat(right);
        }

        public CriterionNode StartsWith(string str)
        {
            return Contains(CreateParameter(str + "%"));
        }

        public CriterionNode EndsWith(string str)
        {
            return Contains(CreateParameter("%" + str));
        }

        public CriterionNode Contains(string str)
        {
            return Contains(CreateParameter("%" + str + "%"));
        }
        public CriterionNode Contains(SqlNClob str)
        {
            return new LikeNode(this.Expression ?? this, str);
        }

        public CriterionNode IsNullOrEmpty()
        {
            return new IsNullOrEmptyNode(this.Expression ?? this);
        }

        public SqlNClob Lower()
        {
            return new SqlNClob { Expression = new FunctionExpression(FunctionView.String.Lower, this.Expression ?? this) };
        }
        public SqlNClob Upper()
        {
            return new SqlNClob { Expression = new FunctionExpression(FunctionView.String.Upper, this.Expression ?? this) };
        }

        public SqlNClob Trim()
        {
            return new SqlNClob { Expression = new FunctionExpression(FunctionView.String.Trim, this.Expression ?? this) };
        }
        public SqlNClob TrimStart()
        {
            return new SqlNClob { Expression = new FunctionExpression(FunctionView.String.LTrim, this.Expression ?? this) };
        }
        public SqlNClob TrimEnd()
        {
            return new SqlNClob { Expression = new FunctionExpression(FunctionView.String.RTrim, this.Expression ?? this) };
        }

        public SqlNClob SubString(int start, int length)
        {
            return SubString(new SqlInt32(start), new SqlInt32(length));
        }
        public SqlNClob SubString(int start, SqlInt32 length)
        {
            return SubString(new SqlInt32(start), length);
        }
        public SqlNClob SubString(SqlInt32 start, int length)
        {
            return SubString(start, new SqlInt32(length));
        }
        public SqlNClob SubString(SqlInt32 start, SqlInt32 length)
        {
            start.Value = start.Value + 1;
            return new SqlNClob { Expression = new FunctionExpression(FunctionView.String.SubString, this.Expression ?? this, start, length) };
        }

        public SqlInt32 IndexOf(string value)
        {
            return IndexOf(CreateParameter(value));
        }
        public SqlInt32 IndexOf(SqlNClob value)
        {
            return new SqlInt32 { Expression = new FunctionExpression(FunctionView.String.IndexOf, this.Expression ?? this, value) };
        }

        public SqlInt32 IndexOf(string value, int start)
        {
            return IndexOf(CreateParameter(value), new SqlInt32(start));
        }
        public SqlInt32 IndexOf(SqlNClob value, SqlInt32 start)
        {
            start.Value = start.Value + 1;
            return new SqlInt32 { Expression = new FunctionExpression(FunctionView.String.IndexOf, this.Expression ?? this, value, start) };
        }

        public SqlNClob Replace(string old, string @new)
        {
            return Replace(CreateParameter(old), CreateParameter(@new));
        }
        public SqlNClob Replace(SqlNClob old, string @new)
        {
            return Replace(old, CreateParameter(@new));
        }
        public SqlNClob Replace(string old, SqlNClob @new)
        {
            return Replace(CreateParameter(old), @new);
        }
        public SqlNClob Replace(SqlNClob old, SqlNClob @new)
        {
            var expr = new SqlNClob();
            expr.Expression = new FunctionExpression(FunctionView.String.Replace, this.Expression ?? this, old, @new);
            return expr;
        }


        public SqlNClob Remove(int start, int length)
        {
            return Remove(new SqlInt32(start), new SqlInt32(length));
        }
        public SqlNClob Remove(int start, SqlInt32 length)
        {
            return Remove(new SqlInt32(start), length);
        }
        public SqlNClob Remove(SqlInt32 start, int length)
        {
            return Remove(start, new SqlInt32(length));
        }
        public SqlNClob Remove(SqlInt32 start, SqlInt32 length)
        {

            start.Value = start.Value + 1;
            var expr = new SqlNClob();
            expr.Expression = new FunctionExpression(FunctionView.String.Remove, this.Expression ?? this, start, length);
            return expr;
        }

        public SqlNClob Remove(Int32 start)
        {
            return Remove(new SqlInt32(start));
        }
        public SqlNClob Remove(SqlInt32 start)
        {
            start.Value = start.Value + 1;
            var expr = new SqlNClob();
            expr.Expression = new FunctionExpression(FunctionView.String.Remove, this.Expression ?? this, start);
            return expr;
        }

        public SqlInt32 Length
        {
            get
            {
                var fn = new FunctionExpression(FunctionView.String.Length, this.Expression ?? this);
                return new SqlInt32 { Expression = fn };
            }
        }

        public SqlNClob Left(int length)
        {
            return Left(new SqlInt32(length));
        }
        public SqlNClob Left(SqlInt32 length)
        {
            var expr = new SqlNClob();
            expr.Expression = new FunctionExpression(FunctionView.String.Left, this.Expression ?? this, length);
            return expr;
        }
        public SqlNClob Right(int start)
        {
            return Right(new SqlInt32(start));
        }
        public SqlNClob Right(SqlInt32 start)
        {

            start.Value = start.Value + 1;
            var expr = new SqlNClob();
            expr.Expression = new FunctionExpression(FunctionView.String.Right, this.Expression ?? this, start);
            return expr;
        }

        public SqlNClob Concat(string str)
        {
            if (!string.IsNullOrEmpty(Value))
            {
                Value = Value + str;
                return this;
            }

            return new SqlNClob { Expression = new FunctionExpression(FunctionView.String.Concat, this.Expression ?? this, CreateParameter(str)) };
        }
        public SqlNClob Concat(SqlNClob str)
        {
            if (!string.IsNullOrEmpty(str.Value))
                return Concat(str.Value);

            return new SqlNClob { Expression = new FunctionExpression(FunctionView.String.Concat, this.Expression ?? this, str) };
        }
    }

    public sealed partial class SqlGuid : SqlObject<SqlGuid, Guid?>
    {
        public SqlGuid() : base(NodeType.SqlObject) { Type = SqlType.Guid; }
        public SqlGuid(string column, string table)
            : base(NodeType.Column)
        {
            Type = SqlType.Guid;
            Table = table;
            Identity = NameIdentity.Get(Type, column);
        }
        public SqlGuid(string parameterName, Guid? value, ParameterDirection direction)
            : base(NodeType.Parameter)
        {
            Type = SqlType.Guid;
            Identity = NameIdentity.Get(Type, parameterName, direction);
            Value = value;
        }

        protected override SqlGuid CreateParameter(Guid? value)
        {
            return new SqlGuid(ParameterName, value, ParameterDirection.Input);
        }

        public new Guid? Value
        {
            get { return base.Value as Guid?; }
            internal set { base.Value = value; }
        }

        #region Equals & NotEquals
        public static CriterionNode operator ==(SqlGuid left, SqlGuid right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlGuid left, SqlGuid right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(SqlGuid left, Guid? right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlGuid left, Guid? right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(Guid? left, SqlGuid right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(Guid? left, SqlGuid right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        #endregion
    }

    public sealed partial class SqlDateTime : SqlObject<SqlDateTime, DateTime?>
    {
       public SqlDateTime() : base(NodeType.SqlObject) { Type = SqlType.DateTime; }
       public SqlDateTime(string column, string table)
            : base(NodeType.Column)
        {
            Type = SqlType.DateTime;
            Table = table;
            Identity = NameIdentity.Get(Type, column);
        }
        public SqlDateTime(string parameterName, DateTime? value, ParameterDirection direction)
            : base(NodeType.Parameter)
        {
            Type = SqlType.DateTime;
            Identity = NameIdentity.Get(Type, parameterName, direction);
            Value = value;
        }
      
        protected override SqlDateTime CreateParameter(DateTime? value)
        {
            return new SqlDateTime(ParameterName, value, ParameterDirection.Input);
        }

        public new DateTime? Value
        {
            get { return base.Value as DateTime?; }
            internal set { base.Value = value; }
        }

        private static void CheckYear(int value)
        {
            value = Math.Abs(value);
            if (value < 1 || value > 10000)
                throw new ArgumentOutOfRangeException("Year must be between 1 and 9999.");
        }
        private static void CheckMonth(int value)
        {
            value = Math.Abs(value);
            if (value < 1 || value > 12)
                throw new ArgumentOutOfRangeException("Month must be between 1 and 12.");
        }
        private static void CheckDay(int value)
        {
            value = Math.Abs(value);
            if (value < 1 || value > 31)
                throw new ArgumentOutOfRangeException("Day must be between 1 and 31.");
        }

        private static void CheckHour(int value)
        {
            value = Math.Abs(value);
            if (value < 1 || value > 24)
                throw new ArgumentOutOfRangeException("Hour must be between 1 and 24.");
        }
        private static void CheckMinute(int value)
        {
            value = Math.Abs(value);
            if (value < 1 || value > 60)
                throw new ArgumentOutOfRangeException("Minute must be between 1 and 60.");
        }
        private static void CheckSecond(int value)
        {
            value = Math.Abs(value);
            if (value < 1 || value > 60)
                throw new ArgumentOutOfRangeException("Second must be between 1 and 60.");
        }

        private SqlInt32 GetDatePart(string fnName)
        {
            return new SqlInt32() { Expression = new FunctionExpression(FunctionView.Get(fnName), this.Expression ?? this) };
        }
        private SqlDateTime AddDatePart(SqlInt32 n, string fnName)
        {

            return new SqlDateTime() { Expression = new FunctionExpression(FunctionView.Get(fnName), this.Expression ?? this, n) };
        }

        static SqlInt64 Arithmetic(SqlDateTime left, string op, SqlDateTime right)
        {
            return new SqlInt64() { Expression = new FunctionExpression(FunctionView.Get(op), left.Expression ?? left, right.Expression ?? right) };
        }

        static SqlInt64 Arithmetic(DateTime? left, string op, SqlDateTime right)
        {
            return new SqlInt64() { Expression = new FunctionExpression(FunctionView.Get(op), right.CreateParameter(left), right) };
        }

        static SqlInt64 Arithmetic(SqlDateTime left, string op, DateTime? right)
        {
            return new SqlInt64() { Expression = new FunctionExpression(FunctionView.Get(op), left, left.CreateParameter(right)) };
        }


        #region Equals & NotEquals
        public static CriterionNode operator ==(SqlDateTime left, SqlDateTime right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlDateTime left, SqlDateTime right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(SqlDateTime left, DateTime? right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlDateTime left, DateTime? right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(DateTime? left, SqlDateTime right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(DateTime? left, SqlDateTime right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        #endregion

        #region GreaterThan & LessThan
        public static CriterionNode operator >(SqlDateTime left, SqlDateTime right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(SqlDateTime left, SqlDateTime right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        public static CriterionNode operator >(SqlDateTime left, DateTime? right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(SqlDateTime left, DateTime? right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        public static CriterionNode operator >(DateTime? left, SqlDateTime right)
        {
            return Compare(left, CompareOperator.GreaterThan, right);
        }

        public static CriterionNode operator <(DateTime? left, SqlDateTime right)
        {
            return Compare(left, CompareOperator.LessThan, right);
        }

        #endregion


        public static SqlInt64 operator -(SqlDateTime left, SqlDateTime right)
        {
            return Arithmetic(left, FunctionType.DateTime.Subtract, right);
        }
        public static SqlInt64 operator -(DateTime? left, SqlDateTime right)
        {
            return Arithmetic(left, FunctionType.DateTime.Subtract, right);
        }
        public static SqlInt64 operator -(SqlDateTime left, DateTime? right)
        {
            return Arithmetic(left, FunctionType.DateTime.Subtract, right);
        }

        #region GreaterThanOrEquals & LessThanOrEquals
        public static CriterionNode operator >=(SqlDateTime left, SqlDateTime right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(SqlDateTime left, SqlDateTime right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        public static CriterionNode operator >=(SqlDateTime left, DateTime? right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(SqlDateTime left, DateTime? right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        public static CriterionNode operator >=(DateTime? left, SqlDateTime right)
        {
            return Compare(left, CompareOperator.GreaterThanOrEquals, right);
        }

        public static CriterionNode operator <=(DateTime? left, SqlDateTime right)
        {
            return Compare(left, CompareOperator.LessThanOrEquals, right);
        }

        #endregion

       

        public static SqlDateTime Current
        {
            get
            {
                return new SqlDateTime { Expression = new FunctionExpression(FunctionView.DateTime.Current) };
            }
        }

        public SqlInt32 Day
        {
            get
            {
                if (IsParameter && Value.HasValue)
                    return new SqlInt32(Value.Value.Day);
                return GetDatePart(FunctionType.DateTime.GetDay);
            }
        }
        public SqlInt32 Month
        {
            get
            {
                if (IsParameter && Value.HasValue)
                    return new SqlInt32(Value.Value.Month);
                return GetDatePart(FunctionType.DateTime.GetMonth);
            }
        }
        public SqlInt32 Year
        {
            get
            {
                if (IsParameter && Value.HasValue)
                    return new SqlInt32(Value.Value.Year);
                return GetDatePart(FunctionType.DateTime.GetYear);
            }
        }

        public SqlInt32 Hour
        {
            get
            {
                if (IsParameter && Value.HasValue)
                    return new SqlInt32(Value.Value.Hour);
                return GetDatePart(FunctionType.DateTime.GetHour);
            }
        }
        public SqlInt32 Minute
        {
            get
            {
                if (IsParameter && Value.HasValue)
                    return new SqlInt32(Value.Value.Minute);
                return GetDatePart(FunctionType.DateTime.GetMinute);
            }
        }
        public SqlInt32 Second
        {
            get
            {
                if (IsParameter && Value.HasValue)
                    return new SqlInt32(Value.Value.Second);
                return GetDatePart(FunctionType.DateTime.GetSecond);
            }
        }


        public SqlInt32 Millisecond
        {
            get
            {
                if (IsParameter && Value.HasValue)
                    return new SqlInt32(Value.Value.Millisecond);
                return GetDatePart(FunctionType.DateTime.GetMillisecond);
            }
        }
        public SqlInt32 DayOfYear
        {
            get
            {
                if (IsParameter && Value.HasValue)
                    return new SqlInt32(Value.Value.DayOfYear);
                return GetDatePart(FunctionType.DateTime.GetDayOfYear);
            }
        }
        public SqlInt32 DayOfWeek
        {
            get
            {
                if (IsParameter && Value.HasValue)
                    return new SqlInt32((int)Value.Value.DayOfWeek);
                return GetDatePart(FunctionType.DateTime.GetDayOfWeek);
            }
        }

        public static SqlDateTime New(SqlInt32 year, SqlInt32 month, SqlInt32 day)
        {
            return new SqlDateTime
            {
                Expression = new FunctionExpression(FunctionView.DateTime.New,year,month,day)
            };
        }
        public static SqlDateTime New(int year, int month, int day)
        {
            CheckYear(year);
            CheckMonth(month);
            CheckDay(day);
            var value = string.Format(fmt,
                year
                , Format(month)
                , Format(day)
                , "00"
                , "00"
                , "00");

            return new SqlDateTime
            {
                Expression = new FunctionExpression(FunctionView.DateTime.New, new SqlString("p", value, ParameterDirection.Input), DateFormat)
            };
        }
        public static SqlDateTime New(SqlInt32 year, SqlInt32 month, SqlInt32 day, SqlInt32 hour, SqlInt32 minute, SqlInt32 second)
        {
            return new SqlDateTime
            {
                Expression = new FunctionExpression(FunctionView.DateTime.New, year, month, day,hour,minute,second)
            };
        }

        static string Format(int n)
        {
            return n > 9 ? n.ToString() : "0" + n.ToString();
        }

        const string fmt = "{0}-{1}-{2} {3}:{4}:{5}";
        public static readonly SqlString DateFormat = new SqlString("p", "'yyyy-mm-dd hh24-mi-ss'", ParameterDirection.Input);

        public static SqlDateTime New(int year, int month, int day,int hour,int minute,int second)
        {
            CheckYear(year);
            CheckMonth(month);
            CheckDay(day);
            CheckHour(hour);
            CheckMinute(minute);
            CheckSecond(second);
            
            var value = string.Format(fmt,
                year
                , Format(month)
                , Format(day)
                , Format(hour)
                , Format(minute)
                , Format(second));

            return new SqlDateTime
            {
                Expression = new FunctionExpression(FunctionView.DateTime.New, new SqlString("p", value, ParameterDirection.Input), DateFormat)
            };
        }

        public SqlDateTime AddYear(SqlInt32 year)
        {
            if (!Node.Equals(null, year) && year.IsParameter && year.Value.HasValue)
                return AddYear(year.Value.Value);

            return AddDatePart(year, FunctionType.DateTime.AddYear);
        }
        public SqlDateTime AddMonth(SqlInt32 month)
        {
            if (!Node.Equals(null, month) && month.IsParameter && month.Value.HasValue)
                return AddMonth(month.Value.Value);
            return AddDatePart(month, FunctionType.DateTime.AddMonth);
        }
        public SqlDateTime AddDay(SqlInt32 day)
        {
            if (!Node.Equals(null, day) && day.IsParameter && day.Value.HasValue)
                return AddDay(day.Value.Value);
            return AddDatePart(day, FunctionType.DateTime.AddDay);
        }
        public SqlDateTime AddHour(SqlInt32 hour)
        {
            if (!Node.Equals(null, hour) && hour.IsParameter && hour.Value.HasValue)
                return AddHour(hour.Value.Value);
            return AddDatePart(hour, FunctionType.DateTime.AddHour);
        }
        public SqlDateTime AddMinute(SqlInt32 minute)
        {
            if (!Node.Equals(null, minute) && minute.IsParameter && minute.Value.HasValue)
                return AddMinute(minute.Value.Value);
            return AddDatePart(minute, FunctionType.DateTime.AddMinute);
        }
        public SqlDateTime AddSecond(SqlInt32 second)
        {
            if (!Node.Equals(null, second) && second.IsParameter && second.Value.HasValue)
                return AddSecond(second.Value.Value);
            return AddDatePart(second, FunctionType.DateTime.AddSecond);
        }


        public SqlDateTime AddYear(int year)
        {
            CheckYear(year);
            if (IsParameter && Value.HasValue)
            {
                Value.Value.AddYears(year);
                return this;
            }
            return AddDatePart(new SqlInt32(year), FunctionType.DateTime.AddYear);
        }
        public SqlDateTime AddMonth(int month)
        {
            CheckMonth(month);
            if (IsParameter && Value.HasValue)
            {
                Value.Value.AddMonths(month);
                return this;
            }
            return AddDatePart(new SqlInt32(month), FunctionType.DateTime.AddMonth);
        }
        public SqlDateTime AddDay(int day)
        {
            CheckDay(day);
            if (IsParameter && Value.HasValue)
            {
                Value.Value.AddDays(day);
                return this;
            }
            return AddDatePart(new SqlInt32(day), FunctionType.DateTime.AddDay);
        }
        public SqlDateTime AddHour(int hour)
        {
            CheckHour(hour);
            if (IsParameter && Value.HasValue)
            {
                Value.Value.AddHours(hour);
                return this;
            }
            return AddDatePart(new SqlInt32(hour), FunctionType.DateTime.AddHour);
        }
        public SqlDateTime AddMinute(int minute)
        {
            CheckMinute(minute);
            if (IsParameter && Value.HasValue)
            {
                Value.Value.AddMinutes(minute);
                return this;
            }
            return AddDatePart(new SqlInt32(minute), FunctionType.DateTime.AddMinute);
        }
        public SqlDateTime AddSecond(int second)
        {
            CheckSecond(second);
            if (IsParameter && Value.HasValue)
            {
                Value.Value.AddSeconds(second);
                return this;
            }
            return AddDatePart(new SqlInt32(second), FunctionType.DateTime.AddSecond);
        }
       
        public SqlInt64 Subtract(SqlDateTime other)
        {

            if (IsParameter && Value.HasValue)
            {
                if (Node.Equals(null, other))
                    return new SqlInt64(Value.Value.Ticks);
                if(other.IsParameter && other.Value.HasValue)
                    return new SqlInt64( (Value.Value - other.Value.Value).Ticks);
            }
            return Arithmetic(this, FunctionType.DateTime.Subtract, other);
        }
        public SqlInt64 Subtract(DateTime? other)
        {
            if (IsParameter && Value.HasValue)
            {
                if (!other.HasValue)
                    return new SqlInt64(Value.Value.Ticks);
                return new SqlInt64((Value.Value - other.Value).Ticks);
            }
            return Arithmetic(this, FunctionType.DateTime.Subtract, other);
        }
    }

    public sealed partial class SqlBinary : SqlObject<SqlBinary, Byte[]>
    {
        public SqlBinary() : base(NodeType.SqlObject) { Type = SqlType.Binary; }
        public SqlBinary(string column, string table)
            : base(NodeType.Column)
        {
            Type = SqlType.Binary;
            Table = table;
            Identity = NameIdentity.Get(Type, column);
        }
        public SqlBinary(string parameterName, Byte[] value, ParameterDirection direction)
            : base(NodeType.Parameter)
        {
            Type = SqlType.Empty;
            Identity = NameIdentity.Get(Type, parameterName, direction);
            Value = value;
        }
      
        protected override SqlBinary CreateParameter(Byte[] value)
        {
            return new SqlBinary(ParameterName, value, ParameterDirection.Input);
        }

        public new Byte[] Value
        {
            get { return base.Value as Byte[]; }
            internal set { base.Value = value; }
        }

        #region Equals & NotEquals
        public static CriterionNode operator ==(SqlBinary left, SqlBinary right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlBinary left, SqlBinary right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(SqlBinary left, byte[] right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlBinary left, byte[] right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(byte[] left, SqlBinary right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(byte[] left, SqlBinary right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        #endregion
    }
    public sealed partial class SqlBlob : SqlObject<SqlBlob, Byte[]>
    {
        public SqlBlob() : base(NodeType.SqlObject) { Type = SqlType.Blob; }
        public SqlBlob(string column, string table)
            : base(NodeType.Column)
        {
            Type = SqlType.Blob;
            Table = table;
            Identity = NameIdentity.Get(Type, column);
        }
        public SqlBlob(string parameterName, Byte[] value, ParameterDirection direction)
            : base(NodeType.Parameter)
        {
            Type = SqlType.Empty;
            Identity = NameIdentity.Get(Type, parameterName, direction);
            Value = value;
        }

        protected override SqlBlob CreateParameter(Byte[] value)
        {
            return new SqlBlob(ParameterName, value, ParameterDirection.Input);
        }

        public new Byte[] Value
        {
            get { return base.Value as Byte[]; }
            internal set { base.Value = value; }
        }

        #region Equals & NotEquals
        public static CriterionNode operator ==(SqlBlob left, SqlBlob right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlBlob left, SqlBlob right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(SqlBlob left, byte[] right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(SqlBlob left, byte[] right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public static CriterionNode operator ==(byte[] left, SqlBlob right)
        {
            return Compare(left, CompareOperator.Equal, right);
        }

        public static CriterionNode operator !=(byte[] left, SqlBlob right)
        {
            return Compare(left, CompareOperator.NotEqual, right);
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        #endregion
    }
}
